<commit_before>/*
* mod_dup - duplicates apache requests
*
* Copyright (C) 2013 Orange
*
* 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.
*/

#pragma once

#include <httpd.h>
#include <http_config.h>
#include <http_request.h>
#include <http_protocol.h>
#include <apr_pools.h>
#include <apr_hooks.h>
#include <queue>
#include <unistd.h>
#include <curl/curl.h>
#include <iostream>
#include <boost/lexical_cast.hpp>

#include "Log.hh"
#include "RequestProcessor.hh"
#include "ThreadPool.hh"

namespace DupModule {

/*
 * Different duplication modes supported by mod_dup
 */
namespace DuplicationType {

    enum eDuplicationType {
        HEADER_ONLY,
        COMPLETE_REQUEST,
        REQUEST_WITH_ANSWER,
    };

    /*
     * Converts the string representation of a DuplicationType into the enum value
     */
    eDuplicationType stringToEnum(const char *value);

    const char* c_HEADER_ONLY =                 "HEADER_ONLY";
    const char* c_COMPLETE_REQUEST =            "COMPLETE_REQUEST";
    const char* c_REQUEST_WITH_ANSWER =         "REQUEST_WITH_ANSWER";
    const char* c_ERROR_ON_STRING_VALUE =       "Invalid Duplication Type Value. Supported Values: HEADER_ONLY | COMPLETE_REQUEST | REQUEST_WITH_ANSWER" ;
};

/**
 * A structure that holds the configuration specific to the location
 */
struct DupConf {

    DupConf();

    tFilterBase::eFilterScope           currentScope;
    DuplicationType::eDuplicationType   currentDuplicationType;

    char                                *dirName;
};

/**
 * @brief Initialize our the processor and thread pool pre-config
 * @param pPool the apache pool
 * @return Always OK
 */
int
preConfig(apr_pool_t * pPool, apr_pool_t * pLog, apr_pool_t * pTemp);

/**
 * @brief allocate a pointer to a string which will hold the path for the dir config if mod_dup is active on it
 * @param pPool the apache pool on which to allocate data
 * @param pDirName the directory name for which to create data
 * @return a void pointer to newly allocated object
 */
void *
createDirConfig(apr_pool_t *pPool, char *pDirName);

/**
 * @brief Initialize logging post-config
 * @param pPool the apache pool
 * @param pServer the corresponding server record
 * @return Always OK
 */
int
postConfig(apr_pool_t * pPool, apr_pool_t * pLog, apr_pool_t * pTemp, server_rec * pServer);

/**
 * @brief Set the destination host and port
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pDestionation the destination in <host>[:<port>] format
 * @return Always DECLINED to let other modules handle the request
 */
const char*
setDestination(cmd_parms* pParams, void* pCfg, const char* pDestination);

/**
 * @brief Set the minimum and maximum number of threads
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pMin the minimum number of threads
 * @param pMax the maximum number of threads
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setThreads(cmd_parms* pParams, void* pCfg, const char* pMin, const char* pMax);

/**
 * @brief Set the timeout for outgoing requests
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pTimeout the timeout for outgoing requests in ms
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setTimeout(cmd_parms* pParams, void* pCfg, const char* pTimeout);

/**
 * @brief Set the minimum and maximum queue size
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pMin the minimum queue size
 * @param pMax the maximum queue size
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setQueue(cmd_parms* pParams, void* pCfg, const char* pMin, const char* pMax);

/**
 * @brief Add a substitution definition
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pField the field on which to do the substitution
 * @param pMatch the regexp matching what should be replaced
 * @param pReplace the value which the match should be replaced with
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setSubstitution(cmd_parms* pParams, void* pCfg, tFilterBase::eFilterScope pScope, const char *pField, const char* pMatch, const char* pReplace);

const char*
setHeaderSubstitution(cmd_parms* pParams, void* pCfg, const char *pField, const char* pMatch, const char* pReplace);

/**
 * @brief Activate duplication
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @return NULL
 */
const char*
setActive(cmd_parms* pParams, void* pCfg);

/**
 * @brief Add a filter definition
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pField the field on which to do the substitution
 * @param pFilter a reg exp which has to match for this request to be duplicated
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setFilter(cmd_parms* pParams, void* pCfg, const char *pType, const char *pField, const char* pFilter);

/**
 * @brief Clean up before the child exits
 */
apr_status_t
cleanUp(void *);

/**
 * @brief init curl and our own thread pool on child init
 * @param pPool the apache pool
 * @param pServer the apache server record
 */
void
childInit(apr_pool_t *pPool, server_rec *pServer);

/**
 * @brief register hooks in apache
 * @param pPool the apache pool
 */
void registerHooks(apr_pool_t *pPool);

}
<commit_msg>Duplication type introduction<commit_after>/*
* mod_dup - duplicates apache requests
*
* Copyright (C) 2013 Orange
*
* 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.
*/

#pragma once

#include <httpd.h>
#include <http_config.h>
#include <http_request.h>
#include <http_protocol.h>
#include <apr_pools.h>
#include <apr_hooks.h>
#include <queue>
#include <unistd.h>
#include <curl/curl.h>
#include <iostream>
#include <boost/lexical_cast.hpp>

#include "Log.hh"
#include "RequestProcessor.hh"
#include "ThreadPool.hh"

namespace DupModule {

/*
 * Different duplication modes supported by mod_dup
 */
namespace DuplicationType {

    enum eDuplicationType {
        HEADER_ONLY,            // Duplication only the HTTP HEADER of matching requests
        COMPLETE_REQUEST,       // Duplication HTTP HEADER AND BODY of matching requests
        REQUEST_WITH_ANSWER,    // Duplication HTTP REQUEST AND ANSWER of matching requests
    };

    /*
     * Converts the string representation of a DuplicationType into the enum value
     */
    eDuplicationType stringToEnum(const char *value);

    const char* c_HEADER_ONLY =                 "HEADER_ONLY";
    const char* c_COMPLETE_REQUEST =            "COMPLETE_REQUEST";
    const char* c_REQUEST_WITH_ANSWER =         "REQUEST_WITH_ANSWER";
    const char* c_ERROR_ON_STRING_VALUE =       "Invalid Duplication Type Value. Supported Values: HEADER_ONLY | COMPLETE_REQUEST | REQUEST_WITH_ANSWER" ;
};

/**
 * A structure that holds the configuration specific to the location
 */
struct DupConf {

    DupConf();

    tFilterBase::eFilterScope           currentScope;
    DuplicationType::eDuplicationType   currentDuplicationType;

    char                                *dirName;
};

/**
 * @brief Initialize our the processor and thread pool pre-config
 * @param pPool the apache pool
 * @return Always OK
 */
int
preConfig(apr_pool_t * pPool, apr_pool_t * pLog, apr_pool_t * pTemp);

/**
 * @brief allocate a pointer to a string which will hold the path for the dir config if mod_dup is active on it
 * @param pPool the apache pool on which to allocate data
 * @param pDirName the directory name for which to create data
 * @return a void pointer to newly allocated object
 */
void *
createDirConfig(apr_pool_t *pPool, char *pDirName);

/**
 * @brief Initialize logging post-config
 * @param pPool the apache pool
 * @param pServer the corresponding server record
 * @return Always OK
 */
int
postConfig(apr_pool_t * pPool, apr_pool_t * pLog, apr_pool_t * pTemp, server_rec * pServer);

/**
 * @brief Set the destination host and port
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pDestionation the destination in <host>[:<port>] format
 * @return Always DECLINED to let other modules handle the request
 */
const char*
setDestination(cmd_parms* pParams, void* pCfg, const char* pDestination);

/**
 * @brief Set the minimum and maximum number of threads
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pMin the minimum number of threads
 * @param pMax the maximum number of threads
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setThreads(cmd_parms* pParams, void* pCfg, const char* pMin, const char* pMax);

/**
 * @brief Set the timeout for outgoing requests
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pTimeout the timeout for outgoing requests in ms
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setTimeout(cmd_parms* pParams, void* pCfg, const char* pTimeout);

/**
 * @brief Set the minimum and maximum queue size
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pMin the minimum queue size
 * @param pMax the maximum queue size
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setQueue(cmd_parms* pParams, void* pCfg, const char* pMin, const char* pMax);

/**
 * @brief Add a substitution definition
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pField the field on which to do the substitution
 * @param pMatch the regexp matching what should be replaced
 * @param pReplace the value which the match should be replaced with
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setSubstitution(cmd_parms* pParams, void* pCfg, tFilterBase::eFilterScope pScope, const char *pField, const char* pMatch, const char* pReplace);

const char*
setHeaderSubstitution(cmd_parms* pParams, void* pCfg, const char *pField, const char* pMatch, const char* pReplace);

/**
 * @brief Activate duplication
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @return NULL
 */
const char*
setActive(cmd_parms* pParams, void* pCfg);

/**
 * @brief Add a filter definition
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pField the field on which to do the substitution
 * @param pFilter a reg exp which has to match for this request to be duplicated
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setFilter(cmd_parms* pParams, void* pCfg, const char *pType, const char *pField, const char* pFilter);

/**
 * @brief Clean up before the child exits
 */
apr_status_t
cleanUp(void *);

/**
 * @brief init curl and our own thread pool on child init
 * @param pPool the apache pool
 * @param pServer the apache server record
 */
void
childInit(apr_pool_t *pPool, server_rec *pServer);

/**
 * @brief register hooks in apache
 * @param pPool the apache pool
 */
void registerHooks(apr_pool_t *pPool);

}
<|endoftext|>


<commit_before>#include <metaSMT/frontend/Array.hpp>
#include <metaSMT/frontend/QF_BV.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/dynamic_bitset.hpp>
#include <string>

using namespace std;
using namespace metaSMT;
using namespace metaSMT::logic;
using namespace metaSMT::logic::Array;
using namespace metaSMT::logic::QF_BV;
namespace proto = boost::proto;
using boost::dynamic_bitset;

BOOST_FIXTURE_TEST_SUITE(Array, Solver_Fixture )

BOOST_AUTO_TEST_CASE( variable_equality )
{
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array x = new_array(elem_width, index_width);
  array y = new_array(elem_width, index_width);

  bool cmp = (x == x);
  BOOST_CHECK( cmp );

  cmp = (x == y);
  BOOST_CHECK( !cmp );

  cmp = (y == x);
  BOOST_CHECK( !cmp );
}

BOOST_AUTO_TEST_CASE( array_equal_t ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);
  array b = new_array(elem_width, index_width);

  assumption( ctx, equal(a, b) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, nequal(a, b) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, nequal(a, b) );
  BOOST_REQUIRE( !solve(ctx) );
}

BOOST_AUTO_TEST_CASE( store_t ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);
  array b = new_array(elem_width, index_width);

  // element
  bitvector e = new_bitvector(elem_width);

  // indices
  bitvector i = new_bitvector(index_width);
  bitvector j = new_bitvector(index_width);

  assumption( ctx, equal(store(a, i, e), store(a, i, e)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, equal(store(a, i, e), store(b, i, e)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, nequal(store(a, i, e), store(b, i, e)) );
  BOOST_REQUIRE( !solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, equal(store(a, i, e), store(a, j, e)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, nequal(store(a, i, e), store(a, j, e)) );
  BOOST_REQUIRE( !solve(ctx) );
}

BOOST_AUTO_TEST_CASE( select_t ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);
  array b = new_array(elem_width, index_width);

  // element
  bitvector e = new_bitvector(elem_width);

  // indices
  bitvector i = new_bitvector(index_width);
  bitvector j = new_bitvector(index_width);

  assumption( ctx, equal(select(a, i), select(a, i)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, equal(select(a, i), select(b, i)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, nequal(select(a, i), select(b, i)) );
  BOOST_REQUIRE( !solve(ctx) );

  assumption( ctx, nequal(a, b) );
  assumption( ctx, nequal(select(a, i), select(b, i)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, equal(select(a, i), select(a, j)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, nequal(select(a, i), select(a, j)) );
  BOOST_REQUIRE( !solve(ctx) );
}

BOOST_AUTO_TEST_CASE( read_write_consistency ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);

  // element
  bitvector e = new_bitvector(elem_width);

  // indices
  bitvector i = new_bitvector(index_width);
  bitvector j = new_bitvector(index_width);

  assumption( ctx, equal(i, j) );
  assumption( ctx, equal(select(store(a, i, e), j), e) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, nequal(select(store(a, i, e), j), e) );
  BOOST_REQUIRE( !solve(ctx) );

  assumption( ctx, nequal(i, j) );
  assumption( ctx, equal( select(store(a, i, e), j), select(a, j) ) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, nequal(i, j) );
  assumption( ctx, nequal( select(store(a, i, e), j), select(a, j) ) );
  BOOST_REQUIRE( !solve(ctx) );
}

BOOST_AUTO_TEST_CASE( read_value_t ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);

  // initialize array: a[i] == i for all i
  unsigned const size = 1 << index_width - 1;
  for ( unsigned u = 0; u < size; ++u ) {
    assertion( ctx, equal(bvuint(u, elem_width), select(a, bvuint(u, index_width))) );
  }

  BOOST_REQUIRE( solve(ctx) );

  // check values
  for ( unsigned u = 0; u < size; ++u ) {
    ContextType::result_type expr =
      evaluate( ctx, select(a, bvuint(u, index_width)) );
    unsigned char vd = read_value( ctx, expr );
    BOOST_CHECK_EQUAL(vd, u);
  }
}

BOOST_AUTO_TEST_CASE( read_value_X ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;
  unsigned const init_value = 42;

  array a = new_array(elem_width, index_width);
  array b = new_array(elem_width, index_width);

  // index
  bitvector i = new_bitvector(index_width);

  // element
  bitvector e = new_bitvector(elem_width);

  assertion( ctx, equal(e, bvuint(init_value, elem_width)) );
  assertion( ctx, equal(b, store(a, i, e)) );
  BOOST_REQUIRE( solve(ctx) );

  // uninitialized read from a[i]
  ContextType::result_type expr = evaluate(ctx, select(a, i));
  try {
    read_value( ctx, expr ).throw_if_X();
    BOOST_FAIL("unreachable");
  }
  catch(...) {
    // std::cerr << "Catched" << '\n';
  }

  // read from b[i] = e
  expr = evaluate(ctx, select(b, i));
  std::string ed = read_value( ctx, e );
  // std::cerr << ed << '\n';
  std::string vd = read_value( ctx, expr );
  // std::cerr << vd << '\n';
  BOOST_REQUIRE_EQUAL(ed, vd);
}

BOOST_AUTO_TEST_CASE( uninitialized_select ) {
  unsigned const elem_width = 32;
  unsigned const index_width = 4;

  // uninitialized array
  array a;

  // element
  bitvector e = new_bitvector(elem_width);

  // index
  bitvector i = new_bitvector(index_width);
  assertion( ctx, equal(i, bvuint(0, index_width)) );

  BOOST_CHECK_THROW(
    assertion(ctx, equal(e, select(a, i)))
  , std::exception
  );
}

BOOST_AUTO_TEST_SUITE_END() //Array

//  vim: ft=cpp:ts=2:sw=2:expandtab
<commit_msg>renamed Array test case read_value_t to read_value_from_select<commit_after>#include <metaSMT/frontend/Array.hpp>
#include <metaSMT/frontend/QF_BV.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/dynamic_bitset.hpp>
#include <string>

using namespace std;
using namespace metaSMT;
using namespace metaSMT::logic;
using namespace metaSMT::logic::Array;
using namespace metaSMT::logic::QF_BV;
namespace proto = boost::proto;
using boost::dynamic_bitset;

BOOST_FIXTURE_TEST_SUITE(Array, Solver_Fixture )

BOOST_AUTO_TEST_CASE( variable_equality )
{
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array x = new_array(elem_width, index_width);
  array y = new_array(elem_width, index_width);

  bool cmp = (x == x);
  BOOST_CHECK( cmp );

  cmp = (x == y);
  BOOST_CHECK( !cmp );

  cmp = (y == x);
  BOOST_CHECK( !cmp );
}

BOOST_AUTO_TEST_CASE( array_equal_t ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);
  array b = new_array(elem_width, index_width);

  assumption( ctx, equal(a, b) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, nequal(a, b) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, nequal(a, b) );
  BOOST_REQUIRE( !solve(ctx) );
}

BOOST_AUTO_TEST_CASE( store_t ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);
  array b = new_array(elem_width, index_width);

  // element
  bitvector e = new_bitvector(elem_width);

  // indices
  bitvector i = new_bitvector(index_width);
  bitvector j = new_bitvector(index_width);

  assumption( ctx, equal(store(a, i, e), store(a, i, e)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, equal(store(a, i, e), store(b, i, e)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, nequal(store(a, i, e), store(b, i, e)) );
  BOOST_REQUIRE( !solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, equal(store(a, i, e), store(a, j, e)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, nequal(store(a, i, e), store(a, j, e)) );
  BOOST_REQUIRE( !solve(ctx) );
}

BOOST_AUTO_TEST_CASE( select_t ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);
  array b = new_array(elem_width, index_width);

  // element
  bitvector e = new_bitvector(elem_width);

  // indices
  bitvector i = new_bitvector(index_width);
  bitvector j = new_bitvector(index_width);

  assumption( ctx, equal(select(a, i), select(a, i)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, equal(select(a, i), select(b, i)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(a, b) );
  assumption( ctx, nequal(select(a, i), select(b, i)) );
  BOOST_REQUIRE( !solve(ctx) );

  assumption( ctx, nequal(a, b) );
  assumption( ctx, nequal(select(a, i), select(b, i)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, equal(select(a, i), select(a, j)) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, nequal(select(a, i), select(a, j)) );
  BOOST_REQUIRE( !solve(ctx) );
}

BOOST_AUTO_TEST_CASE( read_write_consistency ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);

  // element
  bitvector e = new_bitvector(elem_width);

  // indices
  bitvector i = new_bitvector(index_width);
  bitvector j = new_bitvector(index_width);

  assumption( ctx, equal(i, j) );
  assumption( ctx, equal(select(store(a, i, e), j), e) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, equal(i, j) );
  assumption( ctx, nequal(select(store(a, i, e), j), e) );
  BOOST_REQUIRE( !solve(ctx) );

  assumption( ctx, nequal(i, j) );
  assumption( ctx, equal( select(store(a, i, e), j), select(a, j) ) );
  BOOST_REQUIRE( solve(ctx) );

  assumption( ctx, nequal(i, j) );
  assumption( ctx, nequal( select(store(a, i, e), j), select(a, j) ) );
  BOOST_REQUIRE( !solve(ctx) );
}

BOOST_AUTO_TEST_CASE( read_value_from_select ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;

  array a = new_array(elem_width, index_width);

  // initialize array: a[i] == i for all i
  unsigned const size = 1 << index_width - 1;
  for ( unsigned u = 0; u < size; ++u ) {
    assertion( ctx, equal(bvuint(u, elem_width), select(a, bvuint(u, index_width))) );
  }

  BOOST_REQUIRE( solve(ctx) );

  // check values
  for ( unsigned u = 0; u < size; ++u ) {
    ContextType::result_type expr =
      evaluate( ctx, select(a, bvuint(u, index_width)) );
    unsigned char vd = read_value( ctx, expr );
    BOOST_CHECK_EQUAL(vd, u);
  }
}

BOOST_AUTO_TEST_CASE( read_value_X ) {
  unsigned const elem_width = 8;
  unsigned const index_width = 4;
  unsigned const init_value = 42;

  array a = new_array(elem_width, index_width);
  array b = new_array(elem_width, index_width);

  // index
  bitvector i = new_bitvector(index_width);

  // element
  bitvector e = new_bitvector(elem_width);

  assertion( ctx, equal(e, bvuint(init_value, elem_width)) );
  assertion( ctx, equal(b, store(a, i, e)) );
  BOOST_REQUIRE( solve(ctx) );

  // uninitialized read from a[i]
  ContextType::result_type expr = evaluate(ctx, select(a, i));
  try {
    read_value( ctx, expr ).throw_if_X();
    BOOST_FAIL("unreachable");
  }
  catch(...) {
    // std::cerr << "Catched" << '\n';
  }

  // read from b[i] = e
  expr = evaluate(ctx, select(b, i));
  std::string ed = read_value( ctx, e );
  // std::cerr << ed << '\n';
  std::string vd = read_value( ctx, expr );
  // std::cerr << vd << '\n';
  BOOST_REQUIRE_EQUAL(ed, vd);
}

BOOST_AUTO_TEST_CASE( uninitialized_select ) {
  unsigned const elem_width = 32;
  unsigned const index_width = 4;

  // uninitialized array
  array a;

  // element
  bitvector e = new_bitvector(elem_width);

  // index
  bitvector i = new_bitvector(index_width);
  assertion( ctx, equal(i, bvuint(0, index_width)) );

  BOOST_CHECK_THROW(
    assertion(ctx, equal(e, select(a, i)))
  , std::exception
  );
}

BOOST_AUTO_TEST_SUITE_END() //Array

//  vim: ft=cpp:ts=2:sw=2:expandtab
<|endoftext|>


<commit_before>// Copyright (C) 2005-2009 by Jukka Korpela
// Copyright (C) 2009-2013 by David Hoerl
// Copyright (C) 2013 by Martin Moene
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "eng_format.hpp"

#include <iomanip>
#include <sstream>

#include <math.h>
#include <stdlib.h>

/*
 * Note: using fabs() and other math functions in global namespace for
 * best compiler coverage.
 */

/*
 * Note: micro, , may not work everywhere, so you can define a glyph yourself:
 */
#ifndef ENG_FORMAT_MICRO_GLYPH
# define ENG_FORMAT_MICRO_GLYPH ""
#endif

/*
 * Note: if not using signed at the computation of prefix_end below,
 * VC2010 -Wall issues a warning about unsigned and addition overflow.
 * Hence the cast to signed int here.
 */
#define ENG_FORMAT_DIMENSION_OF(a) ( static_cast<int>( sizeof(a) / sizeof(0[a]) ) )

eng_prefixed_t eng_prefixed;
eng_exponential_t eng_exponential;

/*
 * Smallest power of ten for which there is a prefix defined.
 * If the set of prefixes will be extended, change this constant
 * and update the table "prefix".
 */

namespace
{

char const * prefix[] =
{
    "y", "z", "a", "f",
    "p", "n", ENG_FORMAT_MICRO_GLYPH, "m",
    "", "k", "M", "G",
    "T", "P", "E", "Z",
    "Y",
};

char const * exponent[] =
{
    "e-24", "e-21", "e-18", "e-15",
    "e-12", "e-9" , "e-6" , "e-3" ,
    ""   , "e3"  , "e6"  , "e9"  ,
    "e12" , "e15" , "e18" , "e21" ,
    "e24" ,
};

const int prefix_count = ENG_FORMAT_DIMENSION_OF( prefix );
const int prefix_start = -24;
const int prefix_end   = prefix_start + 3 * ( prefix_count - 1 );

#if __cplusplus >= 201103L       // C++11
static_assert( ENG_FORMAT_DIMENSION_OF( prefix ) == ENG_FORMAT_DIMENSION_OF( exponent ), "table sizes must match" );
#endif

/*
 * engineering to exponent notation conversion.
 */
std::string eng2exp( std::string text );

} // anonymous namespace

#ifdef _MSC_VER

namespace
{

#if 1
template <typename T>
long lrint( T const x )
{
    return static_cast<long>( x );
}
#else
__inline long int
lrint ( double flt )
{
    int intgr ;

    _asm
    {
        fld flt
        fistp intgr
    } ;

    return intgr ;
}
#endif
} // anonymous namespace

#endif

/**
 * convert real number to prefixed or exponential notation, optionally followed by a unit.
 */
std::string
to_engineering_string( double value, int digits, bool const exponential, std::string const unit /*= ""*/ )
{
    if ( digits < 3 )
    {
        digits = 3;
    }

    char const * sign;

    if ( value < 0.0 )
    {
        sign = "-";
        value = fabs( value );
    }
    else
    {
        sign = "";
    }

    // correctly round to desired precision
    int expof10 = lrint( floor( log10( value ) ) );

    const int power = digits - 1 - expof10;
    value *= pow( 10.0, power );

    double display;
    const double fract = modf( value, &display );

    if ( fract >= 0.5 )
    {
        display += 1.0;
    }

    value = display * pow( 10.0, -power );  //  expof10 - digits + 1

    if ( expof10 > 0 )
    {
        expof10 = ( expof10 / 3 ) * 3;
    }
    else
    {
        expof10 = ( ( -expof10 + 3 ) / 3 ) * ( -3 );
    }

    value *= pow( 10.0, -expof10 );

    if ( value >= 1000.0 )
    {
        value /= 1000.0;
        expof10 += 3;
    }
    else
    {
        if( value >= 100.0 )
        {
            digits -= 2;
        }
        else
        {
            if( value >= 10.0 )
            {
                digits -= 1;
            }
        }
    }

    std::ostringstream os;

    if( exponential || ( expof10 < prefix_start ) || ( expof10 > prefix_end ) )
    {
        os << sign << std::fixed << std::setprecision( digits - 1 ) << value << "e" << expof10 << ( unit.length() ? " " : "" );
    }
    else
    {
        os << sign << std::fixed << std::setprecision( digits - 1 ) << value << " " << prefix[( expof10 - prefix_start ) / 3];
    }
    return os.str() + unit;
}

/**
 * convert the output of real2eng() into a double.
 */
double from_engineering_string( std::string const text )
{
    return strtod( eng2exp( text ).c_str(), NULL );
}

/**
 * step a value by the smallest possible increment.
 */
std::string step_engineering_string( std::string const text, int digits, bool const exponential, bool const positive )
{
    const double value = from_engineering_string( text );

    if( digits < 3 )
    {
        digits = 3;
    }

    // correctly round to desired precision
    const int expof10 = lrint( floor( log10( value ) ) );
    const int   power = expof10 + 1 - digits;

    const double  inc = pow( 10.0, power ) * ( positive ? +1 : -1 );
    const double  ret = value + inc;

    return to_engineering_string( ret, digits, exponential );
}

namespace
{

/*
 * "k" => "1e3"
 */
std::string prefix2exponent( std::string const pfx )
{
    for( int i = 0; i < prefix_count; ++i )
    {
        if ( pfx == prefix[i] )
        {
            return exponent[i];
        }
    }
    return "";
}

/*
 * "1.23 M" => "1.23e+006"
 * omits everything after prefix.
 */
std::string eng2exp( std::string const text )
{
    std::string::size_type pos = text.find( ' ' );

    if ( std::string::npos == pos )
    {
        return text;
    }

    return text.substr( 0, pos ) + prefix2exponent( text.substr( pos + 1, 1 ) );
}

} // anonymous namespace

// end of file
<commit_msg>Clarify eng2exp()<commit_after>// Copyright (C) 2005-2009 by Jukka Korpela
// Copyright (C) 2009-2013 by David Hoerl
// Copyright (C) 2013 by Martin Moene
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "eng_format.hpp"

#include <iomanip>
#include <sstream>

#include <math.h>
#include <stdlib.h>

/*
 * Note: using fabs() and other math functions in global namespace for
 * best compiler coverage.
 */

/*
 * Note: micro, , may not work everywhere, so you can define a glyph yourself:
 */
#ifndef ENG_FORMAT_MICRO_GLYPH
# define ENG_FORMAT_MICRO_GLYPH ""
#endif

/*
 * Note: if not using signed at the computation of prefix_end below,
 * VC2010 -Wall issues a warning about unsigned and addition overflow.
 * Hence the cast to signed int here.
 */
#define ENG_FORMAT_DIMENSION_OF(a) ( static_cast<int>( sizeof(a) / sizeof(0[a]) ) )

eng_prefixed_t eng_prefixed;
eng_exponential_t eng_exponential;

/*
 * Smallest power of ten for which there is a prefix defined.
 * If the set of prefixes will be extended, change this constant
 * and update the table "prefix".
 */

namespace
{

char const * prefix[] =
{
    "y", "z", "a", "f",
    "p", "n", ENG_FORMAT_MICRO_GLYPH, "m",
    "", "k", "M", "G",
    "T", "P", "E", "Z",
    "Y",
};

char const * exponent[] =
{
    "e-24", "e-21", "e-18", "e-15",
    "e-12", "e-9" , "e-6" , "e-3" ,
    ""   , "e3"  , "e6"  , "e9"  ,
    "e12" , "e15" , "e18" , "e21" ,
    "e24" ,
};

const int prefix_count = ENG_FORMAT_DIMENSION_OF( prefix );
const int prefix_start = -24;
const int prefix_end   = prefix_start + 3 * ( prefix_count - 1 );

#if __cplusplus >= 201103L       // C++11
static_assert( ENG_FORMAT_DIMENSION_OF( prefix ) == ENG_FORMAT_DIMENSION_OF( exponent ), "table sizes must match" );
#endif

/*
 * engineering to exponent notation conversion.
 */
std::string eng2exp( std::string text );

} // anonymous namespace

#ifdef _MSC_VER

namespace
{

#if 1
template <typename T>
long lrint( T const x )
{
    return static_cast<long>( x );
}
#else
__inline long int
lrint ( double flt )
{
    int intgr ;

    _asm
    {
        fld flt
        fistp intgr
    } ;

    return intgr ;
}
#endif
} // anonymous namespace

#endif

/**
 * convert real number to prefixed or exponential notation, optionally followed by a unit.
 */
std::string
to_engineering_string( double value, int digits, bool const exponential, std::string const unit /*= ""*/ )
{
    if ( digits < 3 )
    {
        digits = 3;
    }

    char const * sign;

    if ( value < 0.0 )
    {
        sign = "-";
        value = fabs( value );
    }
    else
    {
        sign = "";
    }

    // correctly round to desired precision
    int expof10 = lrint( floor( log10( value ) ) );

    const int power = digits - 1 - expof10;
    value *= pow( 10.0, power );

    double display;
    const double fract = modf( value, &display );

    if ( fract >= 0.5 )
    {
        display += 1.0;
    }

    value = display * pow( 10.0, -power );  //  expof10 - digits + 1

    if ( expof10 > 0 )
    {
        expof10 = ( expof10 / 3 ) * 3;
    }
    else
    {
        expof10 = ( ( -expof10 + 3 ) / 3 ) * ( -3 );
    }

    value *= pow( 10.0, -expof10 );

    if ( value >= 1000.0 )
    {
        value /= 1000.0;
        expof10 += 3;
    }
    else
    {
        if( value >= 100.0 )
        {
            digits -= 2;
        }
        else
        {
            if( value >= 10.0 )
            {
                digits -= 1;
            }
        }
    }

    std::ostringstream os;

    if( exponential || ( expof10 < prefix_start ) || ( expof10 > prefix_end ) )
    {
        os << sign << std::fixed << std::setprecision( digits - 1 ) << value << "e" << expof10 << ( unit.length() ? " " : "" );
    }
    else
    {
        os << sign << std::fixed << std::setprecision( digits - 1 ) << value << " " << prefix[( expof10 - prefix_start ) / 3];
    }
    return os.str() + unit;
}

/**
 * convert the output of real2eng() into a double.
 */
double from_engineering_string( std::string const text )
{
    return strtod( eng2exp( text ).c_str(), NULL );
}

/**
 * step a value by the smallest possible increment.
 */
std::string step_engineering_string( std::string const text, int digits, bool const exponential, bool const positive )
{
    const double value = from_engineering_string( text );

    if( digits < 3 )
    {
        digits = 3;
    }

    // correctly round to desired precision
    const int expof10 = lrint( floor( log10( value ) ) );
    const int   power = expof10 + 1 - digits;

    const double  inc = pow( 10.0, power ) * ( positive ? +1 : -1 );
    const double  ret = value + inc;

    return to_engineering_string( ret, digits, exponential );
}

namespace
{

/*
 * "k" => "1e3"
 */
std::string prefix2exponent( std::string const pfx )
{
    for( int i = 0; i < prefix_count; ++i )
    {
        if ( pfx == prefix[i] )
        {
            return exponent[i];
        }
    }
    return "";
}

/*
 * Convert engineering presentation to presentation with exponent.
 *
 * The engineering presentation should not contain a unit, as the first letter
 * is interpreted as an SI prefix, e.g. "1 T" is 1e12, not 1 (Tesla).
 *
 * "1.23 M"   => 1.23e+6
 * "1.23 kPa" => 1.23e+3  (ok, but not recommended)
 * "1.23 Pa"  => 1.23e+12 (not what's intended!)
 */
std::string eng2exp( std::string const text )
{
    std::string::size_type pos = text.find( ' ' );

    if ( std::string::npos == pos )
    {
        return text;
    }

    const std::string magnitude  = text.substr( 0, pos );
    const std::string prefix     = text.substr( pos + 1, 1 );

    return magnitude + prefix2exponent( prefix );
}

} // anonymous namespace

// end of file
<|endoftext|>


<commit_before>/*******************************************************************************
Copyright (c) 2014, Jan Koester jan.koester@gmx.net
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
	* Redistributions of source code must retain the above copyright
	  notice, this list of conditions and the following disclaimer.
	* Redistributions in binary form must reproduce the above copyright
	  notice, this list of conditions and the following disclaimer in the
	  documentation and/or other materials provided with the distribution.
	* Neither the name of the <organization> nor the
	  names of its contributors may be used to endorse or promote products
	  derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

#include <iostream>

#include <fcntl.h>
#include <cstdlib>
#include <config.h>
#include <errno.h>

#include "os/os.h"
#include "threadpool.h"

#define READEVENT 0
#define SENDEVENT 1

//#define DEBUG_MUTEX

#include "../event.h"

libhttppp::Event::Event(ServerSocket *serversocket) {
	_ServerSocket = serversocket;
	_ServerSocket->setnonblocking();
	_ServerSocket->listenSocket();
	_EventEndloop = true;
	_Cpool = new ConnectionPool(_ServerSocket);
    _WorkerPool = new ThreadPool;
	_Mutex = new Mutex;
	_firstConnectionContext = NULL;
	_lastConnectionContext = NULL;
    _firstWorkerContext=NULL;
    _lastWorkerContext=NULL;
}

libhttppp::Event::~Event() {
	WSASetEvent(_hCleanupEvent[0]);
	delete   _Cpool;
	delete   _firstConnectionContext;
    delete   _WorkerPool;
    delete   _firstWorkerContext;
  _lastWorkerContext=NULL;
	delete   _Mutex;
	_lastConnectionContext = NULL;
}

void libhttppp::Event::runEventloop() {
	int srvssocket = _ServerSocket->getSocket();
	int maxconnets = _ServerSocket->getMaxconnections();

	SYSInfo sysinfo;
	DWORD threadcount = sysinfo.getNumberOfProcessors() * 2;

	if (WSA_INVALID_EVENT == (_hCleanupEvent[0] = WSACreateEvent()))
	{
		_httpexception.Critical("WSACreateEvent() failed:", WSAGetLastError());
		throw _httpexception;
	}

	try{
		InitializeCriticalSection(&_CriticalSection);
	}catch (...){
		HTTPException hexception;
		hexception.Critical("InitializeCriticalSection raised an exception.\n");
		SetConsoleCtrlHandler(CtrlHandler, FALSE);
		if (_hCleanupEvent[0] != WSA_INVALID_EVENT) {
			WSACloseEvent(_hCleanupEvent[0]);
			_hCleanupEvent[0] = WSA_INVALID_EVENT;
		}
		throw _httpexception;
	}

	while (_EventRestartloop) {
		_EventRestartloop = true;
		_EventEndloop = true;
		WSAResetEvent(_hCleanupEvent[0]);

		_IOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
		if (_IOCP == NULL) {
			_httpexception.Critical("CreateIoCompletionPort() failed to create I/O completion port:",
				GetLastError());
			throw _httpexception;
		}

		SYSInfo sysinfo;
		size_t thrs = sysinfo.getNumberOfProcessors();
		for (size_t i = 0; i < thrs; i++) {
			WorkerContext *curwrkctx = addWorkerContext();
			curwrkctx->_CurThread->Create(WorkerThread, curwrkctx);
		}

		int nRet = 0;
		DWORD dwRecvNumBytes = 0;
		DWORD bytes = 0;

#ifdef Windows
		GUID acceptex_guid = WSAID_ACCEPTEX;
#endif

		ConnectionContext *curcxt = NULL;
		addConnectionContext(&curcxt);

		_IOCP = CreateIoCompletionPort((HANDLE)_ServerSocket->getSocket(), _IOCP, (DWORD_PTR)curcxt, 0);
		if (_IOCP == NULL) {
			_httpexception.Critical("CreateIoCompletionPort() failed: %d\n", GetLastError());
			delConnectionContext(curcxt,NULL);
			throw _httpexception;
		}

		if (curcxt == NULL) {
			_httpexception.Critical("failed to update listen socket to IOCP\n");
			throw _httpexception;
		}

		// Load the AcceptEx extension function from the provider for this socket
		nRet = WSAIoctl(
			_ServerSocket->getSocket(),
			SIO_GET_EXTENSION_FUNCTION_POINTER,
			&acceptex_guid,
			sizeof(acceptex_guid),
			&curcxt->fnAcceptEx,
			sizeof(curcxt->fnAcceptEx),
			&bytes,
			NULL,
			NULL
		);

		if (nRet == SOCKET_ERROR){
			_httpexception.Critical("failed to load AcceptEx: %d\n", WSAGetLastError());
			throw _httpexception;
		}

		/*Disable Buffer in Clientsocket*/
		try {
			ClientSocket *lsock = curcxt->_CurConnection->getClientSocket();
			lsock->disableBuffer();
		}catch(HTTPException &e){
			if (e.isCritical()) {
				throw e;
			}
		}

		//
		// pay close attention to these parameters and buffer lengths
		//

		char buf[BLOCKSIZE];
		nRet = curcxt->fnAcceptEx(_ServerSocket->getSocket(),
			curcxt->_CurConnection->getClientSocket()->getSocket(),
			(LPVOID)(buf),
			BLOCKSIZE - (2 * (sizeof(SOCKADDR_STORAGE) + 16)),
			sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16,
			&dwRecvNumBytes,
			(LPOVERLAPPED) &(curcxt->Overlapped)); //buggy needs impletend in event.h

		if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())) {
			_httpexception.Critical("AcceptEx() failed: %d\n", WSAGetLastError());
			throw _httpexception;
		}

		ConnectionData *cdat = curcxt->_CurConnection->addRecvQueue(buf, dwRecvNumBytes);

		WSAWaitForMultipleEvents(1,_hCleanupEvent, TRUE, WSA_INFINITE, FALSE);
	}

	DeleteCriticalSection(&_CriticalSection);

	if (_hCleanupEvent[0] != WSA_INVALID_EVENT) {
		WSACloseEvent(_hCleanupEvent[0]);
		_hCleanupEvent[0] = WSA_INVALID_EVENT;
	}

	WSACleanup();
	SetConsoleCtrlHandler(CtrlHandler, FALSE);
}

DWORD WINAPI libhttppp::Event::WorkerThread(LPVOID WorkThreadContext) {
	HTTPException httpexepction;
	Event *curenv= (Event*)WorkThreadContext;
	ConnectionContext *curcxt = NULL;
	HANDLE hIOCP = curenv->_IOCP;
	HTTPException httpexception;
	httpexception.Note("Worker starting");
	BOOL bSuccess = FALSE;
	DWORD dwIoSize = 0;
	LPWSAOVERLAPPED lpOverlapped = NULL;
	for(;;) {
		bSuccess = GetQueuedCompletionStatus(
			hIOCP,
			&dwIoSize,
			(PDWORD_PTR)&curcxt,
			(LPOVERLAPPED *)&lpOverlapped,
			INFINITE
		);
		if (!bSuccess)
			httpexception.Error("GetQueuedCompletionStatus() failed: ",GetLastError());

		if (curcxt == NULL) {
			return(0);
		}

		if (curenv->_EventEndloop) {
			return(0);
		}
		std::cout << "test\n";
		std::cout << curcxt->_CurConnection->getRecvData()->getData();
	}
	return(0);
}

BOOL WINAPI libhttppp::Event::CtrlHandler(DWORD dwEvent) {
	switch (dwEvent) {
	case CTRL_BREAK_EVENT:
		_EventRestartloop = true;
	case CTRL_C_EVENT:
	case CTRL_LOGOFF_EVENT:
	case CTRL_SHUTDOWN_EVENT:
	case CTRL_CLOSE_EVENT:
		_EventEndloop = true;
		break;

	default:
		//
		// unknown type--better pass it on.
		//

		return(FALSE);
	}
	return(TRUE);
}<commit_msg>fixed iocp support<commit_after>/*******************************************************************************
Copyright (c) 2014, Jan Koester jan.koester@gmx.net
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
	* Redistributions of source code must retain the above copyright
	  notice, this list of conditions and the following disclaimer.
	* Redistributions in binary form must reproduce the above copyright
	  notice, this list of conditions and the following disclaimer in the
	  documentation and/or other materials provided with the distribution.
	* Neither the name of the <organization> nor the
	  names of its contributors may be used to endorse or promote products
	  derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

#include <iostream>

#include <fcntl.h>
#include <cstdlib>
#include <config.h>
#include <errno.h>

#include "os/os.h"
#include "threadpool.h"

#define READEVENT 0
#define SENDEVENT 1

//#define DEBUG_MUTEX

#include "../event.h"

libhttppp::Event::Event(ServerSocket *serversocket) {
	_ServerSocket = serversocket;
	_ServerSocket->setnonblocking();
	_ServerSocket->listenSocket();
	_EventEndloop = true;
    _WorkerPool = new ThreadPool;
	_Lock = new Lock;
	_firstConnectionContext = NULL;
	_lastConnectionContext = NULL;
    _firstWorkerContext=NULL;
    _lastWorkerContext=NULL;
}

libhttppp::Event::~Event() {
	WSASetEvent(_hCleanupEvent[0]);
	delete   _firstConnectionContext;
    delete   _WorkerPool;
    delete   _firstWorkerContext;
  _lastWorkerContext=NULL;
	delete   _Lock;
	_lastConnectionContext = NULL;
}

void libhttppp::Event::runEventloop() {
	HTTPException httpexception;
	int srvssocket = _ServerSocket->getSocket();
	int maxconnets = _ServerSocket->getMaxconnections();

	SYSInfo sysinfo;
	DWORD threadcount = sysinfo.getNumberOfProcessors() * 2;

	if (WSA_INVALID_EVENT == (_hCleanupEvent[0] = WSACreateEvent()))
	{
		httpexception.Critical("WSACreateEvent() failed:", WSAGetLastError());
		throw httpexception;
	}

	try{
		InitializeCriticalSection(&_CriticalSection);
	}catch (...){
		HTTPException hexception;
		hexception.Critical("InitializeCriticalSection raised an exception.\n");
		SetConsoleCtrlHandler(CtrlHandler, FALSE);
		if (_hCleanupEvent[0] != WSA_INVALID_EVENT) {
			WSACloseEvent(_hCleanupEvent[0]);
			_hCleanupEvent[0] = WSA_INVALID_EVENT;
		}
		throw httpexception;
	}

	while (_EventRestartloop) {
		_EventRestartloop = true;
		_EventEndloop = true;
		WSAResetEvent(_hCleanupEvent[0]);

		_IOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
		if (_IOCP == NULL) {
			httpexception.Critical("CreateIoCompletionPort() failed to create I/O completion port:",
				GetLastError());
			throw httpexception;
		}

		SYSInfo sysinfo;
		size_t thrs = sysinfo.getNumberOfProcessors();
		for (size_t i = 0; i < thrs; i++) {
			WorkerContext *curwrkctx = addWorkerContext();
			curwrkctx->_CurThread->Create(WorkerThread, curwrkctx);
		}

		int nRet = 0;
		DWORD dwRecvNumBytes = 0;
		DWORD bytes = 0;

#ifdef Windows
		GUID acceptex_guid = WSAID_ACCEPTEX;
#endif

		ConnectionContext *curcxt = NULL;
		addConnectionContext(&curcxt);

		_IOCP = CreateIoCompletionPort((HANDLE)_ServerSocket->getSocket(), _IOCP, (DWORD_PTR)curcxt, 0);
		if (_IOCP == NULL) {
			httpexception.Critical("CreateIoCompletionPort() failed: %d\n", GetLastError());
			delConnectionContext(curcxt,NULL);
			throw httpexception;
		}

		if (curcxt == NULL) {
			httpexception.Critical("failed to update listen socket to IOCP\n");
			throw httpexception;
		}

		// Load the AcceptEx extension function from the provider for this socket
		nRet = WSAIoctl(
			_ServerSocket->getSocket(),
			SIO_GET_EXTENSION_FUNCTION_POINTER,
			&acceptex_guid,
			sizeof(acceptex_guid),
			&curcxt->fnAcceptEx,
			sizeof(curcxt->fnAcceptEx),
			&bytes,
			NULL,
			NULL
		);

		if (nRet == SOCKET_ERROR){
			httpexception.Critical("failed to load AcceptEx: %d\n", WSAGetLastError());
			throw httpexception;
		}

		/*Disable Buffer in Clientsocket*/
		try {
			ClientSocket *lsock = curcxt->_CurConnection->getClientSocket();
			lsock->disableBuffer();
		}catch(HTTPException &e){
			if (e.isCritical()) {
				throw e;
			}
		}

		//
		// pay close attention to these parameters and buffer lengths
		//

		char buf[BLOCKSIZE];
		nRet = curcxt->fnAcceptEx(_ServerSocket->getSocket(),
			curcxt->_CurConnection->getClientSocket()->getSocket(),
			(LPVOID)(buf),
			BLOCKSIZE - (2 * (sizeof(SOCKADDR_STORAGE) + 16)),
			sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16,
			&dwRecvNumBytes,
			(LPOVERLAPPED) &(curcxt->Overlapped)); //buggy needs impletend in event.h

		if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())) {
			httpexception.Critical("AcceptEx() failed: %d\n", WSAGetLastError());
			throw httpexception;
		}

		ConnectionData *cdat = curcxt->_CurConnection->addRecvQueue(buf, dwRecvNumBytes);

		WSAWaitForMultipleEvents(1,_hCleanupEvent, TRUE, WSA_INFINITE, FALSE);
	}

	DeleteCriticalSection(&_CriticalSection);

	if (_hCleanupEvent[0] != WSA_INVALID_EVENT) {
		WSACloseEvent(_hCleanupEvent[0]);
		_hCleanupEvent[0] = WSA_INVALID_EVENT;
	}

	WSACleanup();
	SetConsoleCtrlHandler(CtrlHandler, FALSE);
}

DWORD WINAPI libhttppp::Event::WorkerThread(LPVOID WorkThreadContext) {
	HTTPException httpexepction;
	WorkerContext *workerctx = (WorkerContext*)WorkThreadContext;
	Event *curenv = workerctx->_CurEvent;
	ConnectionContext *curcxt = NULL;
	HANDLE hIOCP = curenv->_IOCP;
	HTTPException httpexception;
	httpexception.Note("Worker starting");
	BOOL bSuccess = FALSE;
	DWORD dwIoSize = 0;
	LPWSAOVERLAPPED lpOverlapped = NULL;
	for(;;) {
		bSuccess = GetQueuedCompletionStatus(
			hIOCP,
			&dwIoSize,
			(PDWORD_PTR)&curcxt,
			(LPOVERLAPPED *)&lpOverlapped,
			INFINITE
		);
		if (!bSuccess)
			httpexception.Error("GetQueuedCompletionStatus() failed: ",GetLastError());

		if (curcxt == NULL) {
			return(0);
		}

		if (curenv->_EventEndloop) {
			return(0);
		}
		std::cout << "test\n";
		std::cout << curcxt->_CurConnection->getRecvData()->getData();
	}
	return(0);
}

BOOL WINAPI libhttppp::Event::CtrlHandler(DWORD dwEvent) {
	switch (dwEvent) {
	case CTRL_BREAK_EVENT:
		_EventRestartloop = true;
	case CTRL_C_EVENT:
	case CTRL_LOGOFF_EVENT:
	case CTRL_SHUTDOWN_EVENT:
	case CTRL_CLOSE_EVENT:
		_EventEndloop = true;
		break;

	default:
		//
		// unknown type--better pass it on.
		//

		return(FALSE);
	}
	return(TRUE);
}<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh/elem.h"
#include "libmesh/fe.h"
#include "libmesh/fe_interface.h"
#include "libmesh/enum_to_string.h"

namespace libMesh
{

// ------------------------------------------------------------
// Clough-specific implementations

// Anonymous namespace for local helper functions
namespace {

void clough_nodal_soln(const Elem * elem,
                       const Order order,
                       const std::vector<Number> & elem_soln,
                       std::vector<Number> &       nodal_soln,
                       unsigned Dim)
{
  const unsigned int n_nodes = elem->n_nodes();

  const ElemType elem_type = elem->type();

  nodal_soln.resize(n_nodes);

  const Order totalorder = static_cast<Order>(order + elem->p_level());

  // FEType object to be passed to various FEInterface functions below.
  FEType fe_type(order, CLOUGH);
  FEType p_refined_fe_type(totalorder, CLOUGH);

  switch (totalorder)
    {
      // Piecewise cubic shape functions with linear flux edges
    case SECOND:
      // Piecewise cubic shape functions
    case THIRD:
      {

        const unsigned int n_sf =
          FEInterface::n_shape_functions(fe_type, elem);

        std::vector<Point> refspace_nodes;
        FEBase::get_refspace_nodes(elem_type,refspace_nodes);
        libmesh_assert_equal_to (refspace_nodes.size(), n_nodes);

        for (unsigned int n=0; n<n_nodes; n++)
          {
            libmesh_assert_equal_to (elem_soln.size(), n_sf);

            // Zero before summation
            nodal_soln[n] = 0;

            // u_i = Sum (alpha_i phi_i)
            for (unsigned int i=0; i<n_sf; i++)
              nodal_soln[n] += elem_soln[i] *
                FEInterface::shape(Dim, p_refined_fe_type, elem, i, refspace_nodes[n]);
          }

        return;
      }

    default:
      libmesh_error_msg("ERROR: Invalid total order " << totalorder);
    }
} // clough_nodal_soln()

unsigned int clough_n_dofs(const ElemType t, const Order o)
{
  if (t == INVALID_ELEM)
    return 0;

  switch (o)
    {
      // Piecewise cubic shape functions with linear flux edges
    case SECOND:
      {
        switch (t)
          {
          case TRI6:
            return 9;

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }
      // Piecewise cubic Clough-Tocher element
    case THIRD:
      {
        switch (t)
          {
          case TRI6:
            return 12;

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }

    default:
      libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for CLOUGH FE family!");
    }
} // clough_n_dofs()

unsigned int clough_n_dofs_at_node(const ElemType t,
                                   const Order o,
                                   const unsigned int n)
{
  switch (o)
    {
      // Piecewise cubic shape functions with linear flux edges
    case SECOND:
      {
        switch (t)
          {
            // The 2D Clough-Tocher defined on a 6-noded triangle
          case TRI6:
            {
              switch (n)
                {
                case 0:
                case 1:
                case 2:
                  return 3;

                case 3:
                case 4:
                case 5:
                  return 0;

                default:
                  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI6!");
                }
            }

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }
      // The third-order clough shape functions
    case THIRD:
      {
        switch (t)
          {
            // The 2D Clough-Tocher defined on a 6-noded triangle
          case TRI6:
            {
              switch (n)
                {
                case 0:
                case 1:
                case 2:
                  return 3;

                case 3:
                case 4:
                case 5:
                  return 1;

                default:
                  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI6!");
                }
            }

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }
    default:
      libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for CLOUGH FE family!");
    }
} // clough_n_dofs_at_node()

unsigned int clough_n_dofs_per_elem(const ElemType t, const Order o)
{
  switch (o)
    {
      // Piecewise cubic shape functions with linear flux edges
    case SECOND:
      // The third-order Clough-Tocher shape functions
    case THIRD:
      {
        switch (t)
          {
            // The 2D clough defined on a 6-noded triangle
          case TRI6:
            return 0;

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }

    default:
      libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for CLOUGH FE family!");
    }
} // clough_n_dofs_per_elem()

} // anonymous

  // Do full-specialization of nodal_soln() function for every
  // dimension, instead of explicit instantiation at the end of this
  // file.
  // This could be macro-ified so that it fits on one line...
template <>
void FE<0,CLOUGH>::nodal_soln(const Elem * elem,
                              const Order order,
                              const std::vector<Number> & elem_soln,
                              std::vector<Number> & nodal_soln)
{ clough_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/0); }

template <>
void FE<1,CLOUGH>::nodal_soln(const Elem * elem,
                              const Order order,
                              const std::vector<Number> & elem_soln,
                              std::vector<Number> & nodal_soln)
{ clough_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/1); }

template <>
void FE<2,CLOUGH>::nodal_soln(const Elem * elem,
                              const Order order,
                              const std::vector<Number> & elem_soln,
                              std::vector<Number> & nodal_soln)
{ clough_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/2); }

template <>
void FE<3,CLOUGH>::nodal_soln(const Elem * elem,
                              const Order order,
                              const std::vector<Number> & elem_soln,
                              std::vector<Number> & nodal_soln)
{ clough_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/3); }

// Full specialization of n_dofs() function for every dimension
template <> unsigned int FE<0,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); }
template <> unsigned int FE<1,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); }
template <> unsigned int FE<2,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); }
template <> unsigned int FE<3,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); }

// Full specialization of n_dofs_at_node() function for every dimension.
template <> unsigned int FE<0,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); }
template <> unsigned int FE<1,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); }
template <> unsigned int FE<2,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); }
template <> unsigned int FE<3,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); }

// Full specialization of n_dofs_per_elem() function for every dimension.
template <> unsigned int FE<0,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); }
template <> unsigned int FE<1,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); }
template <> unsigned int FE<2,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); }
template <> unsigned int FE<3,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); }

// Clough FEMs are C^1 continuous
template <> FEContinuity FE<0,CLOUGH>::get_continuity() const { return C_ONE; }
template <> FEContinuity FE<1,CLOUGH>::get_continuity() const { return C_ONE; }
template <> FEContinuity FE<2,CLOUGH>::get_continuity() const { return C_ONE; }
template <> FEContinuity FE<3,CLOUGH>::get_continuity() const { return C_ONE; }

// Clough FEMs are not (currently) hierarchic
template <> bool FE<0,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed
template <> bool FE<1,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed
template <> bool FE<2,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed
template <> bool FE<3,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed

#ifdef LIBMESH_ENABLE_AMR
// compute_constraints() specializations are only needed for 2 and 3D
template <>
void FE<2,CLOUGH>::compute_constraints (DofConstraints & constraints,
                                        DofMap & dof_map,
                                        const unsigned int variable_number,
                                        const Elem * elem)
{ compute_proj_constraints(constraints, dof_map, variable_number, elem); }

template <>
void FE<3,CLOUGH>::compute_constraints (DofConstraints & constraints,
                                        DofMap & dof_map,
                                        const unsigned int variable_number,
                                        const Elem * elem)
{ compute_proj_constraints(constraints, dof_map, variable_number, elem); }
#endif // #ifdef LIBMESH_ENABLE_AMR

// Clough FEM shapes need reinit
template <> bool FE<0,CLOUGH>::shapes_need_reinit() const { return true; }
template <> bool FE<1,CLOUGH>::shapes_need_reinit() const { return true; }
template <> bool FE<2,CLOUGH>::shapes_need_reinit() const { return true; }
template <> bool FE<3,CLOUGH>::shapes_need_reinit() const { return true; }

} // namespace libMesh
<commit_msg>Call new version of FEInterface::shape() in fe_clough.C<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh/elem.h"
#include "libmesh/fe.h"
#include "libmesh/fe_interface.h"
#include "libmesh/enum_to_string.h"

namespace libMesh
{

// ------------------------------------------------------------
// Clough-specific implementations

// Anonymous namespace for local helper functions
namespace {

void clough_nodal_soln(const Elem * elem,
                       const Order order,
                       const std::vector<Number> & elem_soln,
                       std::vector<Number> &       nodal_soln)
{
  const unsigned int n_nodes = elem->n_nodes();

  const ElemType elem_type = elem->type();

  nodal_soln.resize(n_nodes);

  const Order totalorder = static_cast<Order>(order + elem->p_level());

  // FEType object to be passed to various FEInterface functions below.
  FEType fe_type(order, CLOUGH);

  switch (totalorder)
    {
      // Piecewise cubic shape functions with linear flux edges
    case SECOND:
      // Piecewise cubic shape functions
    case THIRD:
      {
        const unsigned int n_sf =
          FEInterface::n_shape_functions(fe_type, elem);

        std::vector<Point> refspace_nodes;
        FEBase::get_refspace_nodes(elem_type,refspace_nodes);
        libmesh_assert_equal_to (refspace_nodes.size(), n_nodes);

        for (unsigned int n=0; n<n_nodes; n++)
          {
            libmesh_assert_equal_to (elem_soln.size(), n_sf);

            // Zero before summation
            nodal_soln[n] = 0;

            // u_i = Sum (alpha_i phi_i)
            for (unsigned int i=0; i<n_sf; i++)
              nodal_soln[n] += elem_soln[i] *
                FEInterface::shape(fe_type, elem, i, refspace_nodes[n]);
          }

        return;
      }

    default:
      libmesh_error_msg("ERROR: Invalid total order " << totalorder);
    }
} // clough_nodal_soln()

unsigned int clough_n_dofs(const ElemType t, const Order o)
{
  if (t == INVALID_ELEM)
    return 0;

  switch (o)
    {
      // Piecewise cubic shape functions with linear flux edges
    case SECOND:
      {
        switch (t)
          {
          case TRI6:
            return 9;

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }
      // Piecewise cubic Clough-Tocher element
    case THIRD:
      {
        switch (t)
          {
          case TRI6:
            return 12;

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }

    default:
      libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for CLOUGH FE family!");
    }
} // clough_n_dofs()

unsigned int clough_n_dofs_at_node(const ElemType t,
                                   const Order o,
                                   const unsigned int n)
{
  switch (o)
    {
      // Piecewise cubic shape functions with linear flux edges
    case SECOND:
      {
        switch (t)
          {
            // The 2D Clough-Tocher defined on a 6-noded triangle
          case TRI6:
            {
              switch (n)
                {
                case 0:
                case 1:
                case 2:
                  return 3;

                case 3:
                case 4:
                case 5:
                  return 0;

                default:
                  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI6!");
                }
            }

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }
      // The third-order clough shape functions
    case THIRD:
      {
        switch (t)
          {
            // The 2D Clough-Tocher defined on a 6-noded triangle
          case TRI6:
            {
              switch (n)
                {
                case 0:
                case 1:
                case 2:
                  return 3;

                case 3:
                case 4:
                case 5:
                  return 1;

                default:
                  libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI6!");
                }
            }

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }
    default:
      libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for CLOUGH FE family!");
    }
} // clough_n_dofs_at_node()

unsigned int clough_n_dofs_per_elem(const ElemType t, const Order o)
{
  switch (o)
    {
      // Piecewise cubic shape functions with linear flux edges
    case SECOND:
      // The third-order Clough-Tocher shape functions
    case THIRD:
      {
        switch (t)
          {
            // The 2D clough defined on a 6-noded triangle
          case TRI6:
            return 0;

          default:
            libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
          }
      }

    default:
      libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for CLOUGH FE family!");
    }
} // clough_n_dofs_per_elem()

} // anonymous

  // Do full-specialization of nodal_soln() function for every
  // dimension, instead of explicit instantiation at the end of this
  // file.
  // This could be macro-ified so that it fits on one line...
template <>
void FE<0,CLOUGH>::nodal_soln(const Elem * elem,
                              const Order order,
                              const std::vector<Number> & elem_soln,
                              std::vector<Number> & nodal_soln)
{ clough_nodal_soln(elem, order, elem_soln, nodal_soln); }

template <>
void FE<1,CLOUGH>::nodal_soln(const Elem * elem,
                              const Order order,
                              const std::vector<Number> & elem_soln,
                              std::vector<Number> & nodal_soln)
{ clough_nodal_soln(elem, order, elem_soln, nodal_soln); }

template <>
void FE<2,CLOUGH>::nodal_soln(const Elem * elem,
                              const Order order,
                              const std::vector<Number> & elem_soln,
                              std::vector<Number> & nodal_soln)
{ clough_nodal_soln(elem, order, elem_soln, nodal_soln); }

template <>
void FE<3,CLOUGH>::nodal_soln(const Elem * elem,
                              const Order order,
                              const std::vector<Number> & elem_soln,
                              std::vector<Number> & nodal_soln)
{ clough_nodal_soln(elem, order, elem_soln, nodal_soln); }

// Full specialization of n_dofs() function for every dimension
template <> unsigned int FE<0,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); }
template <> unsigned int FE<1,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); }
template <> unsigned int FE<2,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); }
template <> unsigned int FE<3,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); }

// Full specialization of n_dofs_at_node() function for every dimension.
template <> unsigned int FE<0,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); }
template <> unsigned int FE<1,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); }
template <> unsigned int FE<2,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); }
template <> unsigned int FE<3,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); }

// Full specialization of n_dofs_per_elem() function for every dimension.
template <> unsigned int FE<0,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); }
template <> unsigned int FE<1,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); }
template <> unsigned int FE<2,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); }
template <> unsigned int FE<3,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); }

// Clough FEMs are C^1 continuous
template <> FEContinuity FE<0,CLOUGH>::get_continuity() const { return C_ONE; }
template <> FEContinuity FE<1,CLOUGH>::get_continuity() const { return C_ONE; }
template <> FEContinuity FE<2,CLOUGH>::get_continuity() const { return C_ONE; }
template <> FEContinuity FE<3,CLOUGH>::get_continuity() const { return C_ONE; }

// Clough FEMs are not (currently) hierarchic
template <> bool FE<0,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed
template <> bool FE<1,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed
template <> bool FE<2,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed
template <> bool FE<3,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed

#ifdef LIBMESH_ENABLE_AMR
// compute_constraints() specializations are only needed for 2 and 3D
template <>
void FE<2,CLOUGH>::compute_constraints (DofConstraints & constraints,
                                        DofMap & dof_map,
                                        const unsigned int variable_number,
                                        const Elem * elem)
{ compute_proj_constraints(constraints, dof_map, variable_number, elem); }

template <>
void FE<3,CLOUGH>::compute_constraints (DofConstraints & constraints,
                                        DofMap & dof_map,
                                        const unsigned int variable_number,
                                        const Elem * elem)
{ compute_proj_constraints(constraints, dof_map, variable_number, elem); }
#endif // #ifdef LIBMESH_ENABLE_AMR

// Clough FEM shapes need reinit
template <> bool FE<0,CLOUGH>::shapes_need_reinit() const { return true; }
template <> bool FE<1,CLOUGH>::shapes_need_reinit() const { return true; }
template <> bool FE<2,CLOUGH>::shapes_need_reinit() const { return true; }
template <> bool FE<3,CLOUGH>::shapes_need_reinit() const { return true; }

} // namespace libMesh
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
 *  Main authors:
 *     Guido Tack <tack@gecode.org>
 *  Modified:
 *     Laurent Perron (lperron@google.com)
 *
 *  Copyright:
 *     Guido Tack, 2007
 *
 *
 *  This file is part of Gecode, the generic constraint
 *  development environment:
 *     http://www.gecode.org
 *
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include <iostream>
#include <fstream>
#include <cstring>
#include "base/commandlineflags.h"
#include "base/commandlineflags.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/stringprintf.h"
#include "flatzinc/flatzinc.h"

DEFINE_int32(log_frequency, 100000, "Search log frequency");
DEFINE_bool(log, false, "Show search log");
DECLARE_bool(log_prefix);

namespace operations_research {
void Run(const std::string& file) {
  FlatZincModel fz_model;
  if (file == "-") {
    fz_model.Parse(std::cin);
  } else {
    fz_model.Parse(file);
  }

  fz_model.Solve(FLAGS_log_frequency, FLAGS_log);
  LOG(INFO) << fz_model.DebugString();
}
}

int main(int argc, char** argv) {
  FLAGS_log_prefix=false;
  google::ParseCommandLineFlags(&argc, &argv, true);
  if (argc <= 1) {
    LOG(ERROR) << "Usage: " << argv[0] << " <file>";
    exit(EXIT_FAILURE);
  }
  operations_research::Run(argv[1]);
  return 0;
}

<commit_msg>more work on flatzinc support<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
 *  Main authors:
 *     Guido Tack <tack@gecode.org>
 *  Modified:
 *     Laurent Perron (lperron@google.com)
 *
 *  Copyright:
 *     Guido Tack, 2007
 *
 *
 *  This file is part of Gecode, the generic constraint
 *  development environment:
 *     http://www.gecode.org
 *
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include <iostream>
#include <fstream>
#include <cstring>
#include "base/commandlineflags.h"
#include "base/commandlineflags.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/stringprintf.h"
#include "flatzinc/flatzinc.h"

DEFINE_int32(log_frequency, 100000, "Search log frequency");
DEFINE_bool(log, false, "Show search log");
DECLARE_bool(log_prefix);

namespace operations_research {
void Run(const std::string& file) {
  FlatZincModel fz_model;
  if (file == "-") {
    fz_model.Parse(std::cin);
  } else {
    fz_model.Parse(file);
  }

  fz_model.Solve(FLAGS_log_frequency, FLAGS_log);
  std::cout << fz_model.DebugString() << std::endl
            << "----------" << std::endl;
}
}

int main(int argc, char** argv) {
  FLAGS_log_prefix=false;
  google::ParseCommandLineFlags(&argc, &argv, true);
  if (argc <= 1) {
    LOG(ERROR) << "Usage: " << argv[0] << " <file>";
    exit(EXIT_FAILURE);
  }
  operations_research::Run(argv[1]);
  return 0;
}

<|endoftext|>


<commit_before>/*
  Copyright (c) 2012 Stuart Walsh

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
*/

#include <fnmatch.h>

#include "stdinc.h"
#include "nuhmask.h"

NuhMask::NuhMask()
{
  Logging::trace << "Created NuhMask: " << this << Logging::endl;
}

NuhMask::NuhMask(const string& mask)
{
  parse_mask(mask);
}

NuhMask::~NuhMask()
{
  Logging::trace << "Destroyed NuhMask: " << this << Logging::endl;
}

void NuhMask::parse_mask(const string& mask)
{
  full_mask = mask;
  size_t pos, last;

  last = pos = mask.find_first_of('!');
  if(pos == string::npos || pos == 0)
    name = "*";
  else
    name = mask.substr(0, pos).c_str();

  if(last == string::npos)
    last = 0;
  else
    last++;

  pos = mask.find_first_of('@', last);
  if(pos == string::npos || pos == last)
    username = "*";
  else
    username = mask.substr(last, pos - last).c_str();

  last = pos;
  if(last == string::npos)
    last = 0;
  else
    last++;

  host = mask.substr(last, pos - last);
  if(host.empty())
    host = "*";
}

string NuhMask::str() const
{
  stringstream ss;

  ss << name << "!" << username << "@" << host;

  return ss.str();
}

bool NuhMask::match(const NuhMask& right)
{
  const char *pat = this->str().c_str();
  const char *det = right.str().c_str();
  int ret = fnmatch(pat, det, FNM_NOESCAPE);
  Logging::debug << "NuhMask Match: " << pat << " " << det << Logging::endl;
  return ret == 0 ? true : false;
}

bool NuhMask::match(const ClientPtr right)
{
  NuhMask r(right->str().c_str());
  return this->match(r);
}
<commit_msg>normalize nuhmask to common irc strings in match<commit_after>/*
  Copyright (c) 2012 Stuart Walsh

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
*/

#include <fnmatch.h>

#include "stdinc.h"
#include "nuhmask.h"

NuhMask::NuhMask()
{
  Logging::trace << "Created NuhMask: " << this << Logging::endl;
}

NuhMask::NuhMask(const string& mask)
{
  parse_mask(mask);
}

NuhMask::~NuhMask()
{
  Logging::trace << "Destroyed NuhMask: " << this << Logging::endl;
}

void NuhMask::parse_mask(const string& mask)
{
  full_mask = mask;
  size_t pos, last;

  last = pos = mask.find_first_of('!');
  if(pos == string::npos || pos == 0)
    name = "*";
  else
    name = mask.substr(0, pos).c_str();

  if(last == string::npos)
    last = 0;
  else
    last++;

  pos = mask.find_first_of('@', last);
  if(pos == string::npos || pos == last)
    username = "*";
  else
    username = mask.substr(last, pos - last).c_str();

  last = pos;
  if(last == string::npos)
    last = 0;
  else
    last++;

  host = mask.substr(last, pos - last);
  if(host.empty())
    host = "*";
}

string NuhMask::str() const
{
  stringstream ss;

  ss << name << "!" << username << "@" << host;

  return ss.str();
}

bool NuhMask::match(const NuhMask& right)
{
  std::string spat(this->str());
  std::transform(spat.begin(), spat.end(), spat.begin(), to_upper);
  const char *pat = spat.c_str();

  std::string sdet(right.str());
  std::transform(sdet.begin(), sdet.end(), sdet.begin(), to_upper);
  const char *det = sdet.c_str();

  int ret = fnmatch(pat, det, FNM_NOESCAPE | FNM_CASEFOLD);
  bool ismatch = ret == 0 ? true : false;

  Logging::debug << "NuhMask " << det << " ";

  if(ismatch)
    Logging::debug << "Matched";
  else
    Logging::debug << "No Match";

  Logging::debug << " " << pat << Logging::endl;

  return ismatch;
}

bool NuhMask::match(const ClientPtr right)
{
  NuhMask r(right->str().c_str());
  return this->match(r);
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.

#include <signal.h>

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

#include "ScopedLocalRef.h"
#include "UniquePtr.h"
#include "jni.h"
#include "logging.h"
#include "toStringArray.h"

// Determine whether or not the specified method is public.
static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
  ScopedLocalRef<jobject> reflected(env, env->ToReflectedMethod(clazz,
      method_id, JNI_FALSE));
  if (reflected.get() == NULL) {
    fprintf(stderr, "Unable to get reflected method\n");
    return false;
  }
  // We now have a Method instance.  We need to call its
  // getModifiers() method.
  ScopedLocalRef<jclass> method(env,
      env->FindClass("java/lang/reflect/Method"));
  if (method.get() == NULL) {
    fprintf(stderr, "Unable to find class Method\n");
    return false;
  }
  static const int PUBLIC = 0x0001;   // java.lang.reflect.Modifiers.PUBLIC
  jmethodID get_modifiers = env->GetMethodID(method.get(), "getModifiers", "()I");
  if (get_modifiers == NULL) {
    fprintf(stderr, "Unable to find reflect.Method.getModifiers\n");
    return false;
  }
  int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
  if ((modifiers & PUBLIC) == 0) {
    return false;
  }
  return true;
}

static int InvokeMain(JNIEnv* env, int argc, char** argv) {
  // We want to call main() with a String array with our arguments in
  // it.  Create an array and populate it.  Note argv[0] is not
  // included.
  ScopedLocalRef<jobjectArray> args(env, toStringArray(env, argv + 1));
  if (args.get() == NULL) {
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  // Find [class].main(String[]).

  // Convert "com.android.Blah" to "com/android/Blah".
  std::string class_name(argv[0]);
  std::replace(class_name.begin(), class_name.end(), '.', '/');

  ScopedLocalRef<jclass> klass(env, env->FindClass(class_name.c_str()));
  if (klass.get() == NULL) {
    fprintf(stderr, "Unable to locate class '%s'\n", class_name.c_str());
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  jmethodID method = env->GetStaticMethodID(klass.get(), "main", "([Ljava/lang/String;)V");
  if (method == NULL) {
    fprintf(stderr, "Unable to find static main(String[]) in '%s'\n", class_name.c_str());
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  // Make sure the method is public.  JNI doesn't prevent us from
  // calling a private method, so we have to check it explicitly.
  if (!IsMethodPublic(env, klass.get(), method)) {
    fprintf(stderr, "Sorry, main() is not public in '%s'\n", class_name.c_str());
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  // Invoke main().
  env->CallStaticVoidMethod(klass.get(), method, args.get());
  return EXIT_SUCCESS;
}

// Parse arguments.  Most of it just gets passed through to the VM.
// The JNI spec defines a handful of standard arguments.
int main(int argc, char** argv) {
  setvbuf(stdout, NULL, _IONBF, 0);

  // Skip over argv[0].
  argv++;
  argc--;

  // If we're adding any additional stuff, e.g. function hook specifiers,
  // add them to the count here.
  //
  // We're over-allocating, because this includes the options to the VM
  // plus the options to the program.
  int option_count = argc;
  UniquePtr<JavaVMOption[]> options(new JavaVMOption[option_count]());

  // Copy options over.  Everything up to the name of the class starts
  // with a '-' (the function hook stuff is strictly internal).
  //
  // [Do we need to catch & handle "-jar" here?]
  bool need_extra = false;
  int curr_opt, arg_idx;
  for (curr_opt = arg_idx = 0; arg_idx < argc; arg_idx++) {
    if (argv[arg_idx][0] != '-' && !need_extra) {
      break;
    }
    options[curr_opt++].optionString = argv[arg_idx];

    // Some options require an additional argument.
    need_extra = false;
    if (strcmp(argv[arg_idx], "-classpath") == 0 || strcmp(argv[arg_idx], "-cp") == 0) {
      // others?
      need_extra = true;
    }
  }

  if (need_extra) {
    fprintf(stderr, "VM requires value after last option flag\n");
    return EXIT_FAILURE;
  }

  // Make sure they provided a class name.  We do this after VM init
  // so that things like "-Xrunjdwp:help" have the opportunity to emit
  // a usage statement.
  if (arg_idx == argc) {
    fprintf(stderr, "Class name required\n");
    return EXIT_FAILURE;
  }

  // insert additional internal options here

  DCHECK_LE(curr_opt, option_count);

  JavaVMInitArgs init_args;
  init_args.version = JNI_VERSION_1_6;
  init_args.options = options.get();
  init_args.nOptions = curr_opt;
  init_args.ignoreUnrecognized = JNI_FALSE;

  // Start VM.  The current thread becomes the main thread of the VM.
  JavaVM* vm = NULL;
  JNIEnv* env = NULL;
  if (JNI_CreateJavaVM(&vm, &env, &init_args) != JNI_OK) {
    fprintf(stderr, "VM init failed (check log file)\n");
    return EXIT_FAILURE;
  }

  int rc = InvokeMain(env, argc - arg_idx, &argv[arg_idx]);

  if (vm->DetachCurrentThread() != JNI_OK) {
    fprintf(stderr, "Warning: unable to detach main thread\n");
    rc = EXIT_FAILURE;
  }

  if (vm->DestroyJavaVM() != 0) {
    fprintf(stderr, "Warning: VM did not shut down cleanly\n");
    rc = EXIT_FAILURE;
  }

  return rc;
}
<commit_msg>Ensure we exit with EXIT_FAILURE if the main thread had an uncaught exception.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.

#include <signal.h>

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

#include "ScopedLocalRef.h"
#include "UniquePtr.h"
#include "jni.h"
#include "logging.h"
#include "toStringArray.h"

// Determine whether or not the specified method is public.
static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
  ScopedLocalRef<jobject> reflected(env, env->ToReflectedMethod(clazz, method_id, JNI_FALSE));
  if (reflected.get() == NULL) {
    fprintf(stderr, "Unable to get reflected method\n");
    return false;
  }
  // We now have a Method instance.  We need to call its
  // getModifiers() method.
  ScopedLocalRef<jclass> method(env, env->FindClass("java/lang/reflect/Method"));
  if (method.get() == NULL) {
    fprintf(stderr, "Unable to find class Method\n");
    return false;
  }
  static const int PUBLIC = 0x0001;   // java.lang.reflect.Modifiers.PUBLIC
  jmethodID get_modifiers = env->GetMethodID(method.get(), "getModifiers", "()I");
  if (get_modifiers == NULL) {
    fprintf(stderr, "Unable to find reflect.Method.getModifiers\n");
    return false;
  }
  int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
  if ((modifiers & PUBLIC) == 0) {
    return false;
  }
  return true;
}

static int InvokeMain(JNIEnv* env, int argc, char** argv) {
  // We want to call main() with a String array with our arguments in
  // it.  Create an array and populate it.  Note argv[0] is not
  // included.
  ScopedLocalRef<jobjectArray> args(env, toStringArray(env, argv + 1));
  if (args.get() == NULL) {
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  // Find [class].main(String[]).

  // Convert "com.android.Blah" to "com/android/Blah".
  std::string class_name(argv[0]);
  std::replace(class_name.begin(), class_name.end(), '.', '/');

  ScopedLocalRef<jclass> klass(env, env->FindClass(class_name.c_str()));
  if (klass.get() == NULL) {
    fprintf(stderr, "Unable to locate class '%s'\n", class_name.c_str());
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  jmethodID method = env->GetStaticMethodID(klass.get(), "main", "([Ljava/lang/String;)V");
  if (method == NULL) {
    fprintf(stderr, "Unable to find static main(String[]) in '%s'\n", class_name.c_str());
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  // Make sure the method is public.  JNI doesn't prevent us from
  // calling a private method, so we have to check it explicitly.
  if (!IsMethodPublic(env, klass.get(), method)) {
    fprintf(stderr, "Sorry, main() is not public in '%s'\n", class_name.c_str());
    env->ExceptionDescribe();
    return EXIT_FAILURE;
  }

  // Invoke main().
  env->CallStaticVoidMethod(klass.get(), method, args.get());

  // Check whether there was an uncaught exception. We don't log any uncaught exception here;
  // detaching this thread will do that for us, but it will clear the exception (and invalidate
  // our JNIEnv), so we need to check here.
  return env->ExceptionCheck() ? EXIT_FAILURE : EXIT_SUCCESS;
}

// Parse arguments.  Most of it just gets passed through to the VM.
// The JNI spec defines a handful of standard arguments.
int main(int argc, char** argv) {
  setvbuf(stdout, NULL, _IONBF, 0);

  // Skip over argv[0].
  argv++;
  argc--;

  // If we're adding any additional stuff, e.g. function hook specifiers,
  // add them to the count here.
  //
  // We're over-allocating, because this includes the options to the VM
  // plus the options to the program.
  int option_count = argc;
  UniquePtr<JavaVMOption[]> options(new JavaVMOption[option_count]());

  // Copy options over.  Everything up to the name of the class starts
  // with a '-' (the function hook stuff is strictly internal).
  //
  // [Do we need to catch & handle "-jar" here?]
  bool need_extra = false;
  int curr_opt, arg_idx;
  for (curr_opt = arg_idx = 0; arg_idx < argc; arg_idx++) {
    if (argv[arg_idx][0] != '-' && !need_extra) {
      break;
    }
    options[curr_opt++].optionString = argv[arg_idx];

    // Some options require an additional argument.
    need_extra = false;
    if (strcmp(argv[arg_idx], "-classpath") == 0 || strcmp(argv[arg_idx], "-cp") == 0) {
      // others?
      need_extra = true;
    }
  }

  if (need_extra) {
    fprintf(stderr, "VM requires value after last option flag\n");
    return EXIT_FAILURE;
  }

  // Make sure they provided a class name.  We do this after VM init
  // so that things like "-Xrunjdwp:help" have the opportunity to emit
  // a usage statement.
  if (arg_idx == argc) {
    fprintf(stderr, "Class name required\n");
    return EXIT_FAILURE;
  }

  // insert additional internal options here

  DCHECK_LE(curr_opt, option_count);

  JavaVMInitArgs init_args;
  init_args.version = JNI_VERSION_1_6;
  init_args.options = options.get();
  init_args.nOptions = curr_opt;
  init_args.ignoreUnrecognized = JNI_FALSE;

  // Start VM.  The current thread becomes the main thread of the VM.
  JavaVM* vm = NULL;
  JNIEnv* env = NULL;
  if (JNI_CreateJavaVM(&vm, &env, &init_args) != JNI_OK) {
    fprintf(stderr, "VM init failed (check log file)\n");
    return EXIT_FAILURE;
  }

  int rc = InvokeMain(env, argc - arg_idx, &argv[arg_idx]);

  if (vm->DetachCurrentThread() != JNI_OK) {
    fprintf(stderr, "Warning: unable to detach main thread\n");
    rc = EXIT_FAILURE;
  }

  if (vm->DestroyJavaVM() != 0) {
    fprintf(stderr, "Warning: VM did not shut down cleanly\n");
    rc = EXIT_FAILURE;
  }

  return rc;
}
<|endoftext|>