<commit_before>/*
 * A command line binary for the ray tracer.
 * Autor: Dino Wernli
 */

#include <fstream>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/text_format.h>
#include <memory>
#include <streambuf>
#include <string>
#include <thread>

#include "listener/bmp_exporter.h"
#include "listener/ppm_exporter.h"
#include "listener/progress_listener.h"
#include "listener/raytracer_window.h"
#include "proto/config/renderer_config.pb.h"
#include "proto/config/scene_config.pb.h"
#include "proto/scene/scene_data.pb.h"
#include "renderer/renderer.h"
#include "scene/scene.h"

using raytracer::RendererConfig;
using raytracer::SceneConfig;

// Renderer config flags.
DEFINE_bool(shadows, true, "Whether or not shadows are rendered");

DEFINE_uint64(recursion_depth, 10, "How deep to evaluate reflective and "
                                   "refractive rays");

DEFINE_uint64(rays_per_pixel, 1, "The number of randomly jittered rays to "
                                 "shoot through each pixel");

DEFINE_bool(use_kd_tree, true, "Whether or not to use a KdTree in the scene");

DEFINE_int32(kd_tree_visualization_depth, -1, "How deep in the tree to "
                                              "visualize splitting planes");

DEFINE_uint64(worker_threads, 8, "Number of rendering worker threads to use");

DEFINE_string(sampler_type, "", "The type of sampler to use. Legal values are "
                                "'scanline' and 'progressive'");

DEFINE_string(splitting_strategy, "", "The strategy to use for splitting in the"
                                      " KdTree. Only has effect if use_kd_tree "
                                      "is true. Legal values are 'midpoint'");

// Camera config flags.
DEFINE_int32(image_resolution_x, -1, "Optional override for the horizontal "
                                      "resolution of the image");

DEFINE_int32(image_resolution_y, -1, "Optional override for the vertical "
                                      "resolution of the image");

// Output flags.
DEFINE_string(bmp_file, "image", "If <file> is passed, a BMP image will be "
                                  "saved at 'output/<file>.bmp'");

DEFINE_string(ppm_file, "", "If <file> is passed, a PPM image will be saved at "
                            "'output/<file>.ppm'");

DEFINE_string(scene_data, "data/scene/quadrics_tori.sd",
                          "A file from which to parse the items in the scene");

DEFINE_bool(gui, false, "Whether or not to start the GLUT front end");

/* General Todos:

TODO(dinow): Add support for building and running binaries and single tests in
             scons. Add multiple targets.
TODO(dinow): Implement surface area heuristics for KdTree splitting
TODO(dinow): Fix supersampling (not all identical, but distribute them in pixel
TODO(dinow): Implement adaptive supersampling
TODO(dinow): Add textures, perlin noise, bump maps, skyboxes, path tracing
TODO(dinow): Add possibility to load renderer config from file.
TODO(dinow): Rename proto namespace to "config" or "proto".
TODO(dinow): Put everything else in namespace "raytracer".
TODO(dinow): Implement a webserver.
TODO(dinow): Implement statistics (intersection counting).
TODO(dinow): Remove the default values from the object constructors.
             Leave them only in the protos. Or leave them in both but always
             pass the arguments.
*/

bool LoadSceneData(const std::string& path, raytracer::SceneData* output) {
  std::ifstream stream(path);
  if (!stream.is_open()) {
    return false;
  }
  std::string string((std::istreambuf_iterator<char>(stream)),
                      std::istreambuf_iterator<char>());
  return google::protobuf::TextFormat::ParseFromString(string, output);
}

int main(int argc, char **argv) {
  // LOG(INFO): Always logged.
  // DVLOG(i): Only compiled in if DEBUG flag set.
  //
  // Run <binary name> --logtostderr to see log output.
  // Run <binary name> --logtostderr --v=<i> for DVLOG(j) message for j <= i.
  google::InitGoogleLogging(argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  // Load the configuration from the passed arguments.
  SceneConfig scene_config;
  if (FLAGS_use_kd_tree) {
    scene_config.mutable_kd_tree_config();
  }
  if (FLAGS_scene_data.empty()) {
    LOG(ERROR) << "Failed to load scene data, no file provided";
    return EXIT_FAILURE;
  }
  if (LoadSceneData(FLAGS_scene_data, scene_config.mutable_scene_data())) {
    LOG(INFO) << "Loaded scene data from: " << FLAGS_scene_data;
  } else {
    LOG(ERROR) << "Failed to load scene data from: " << FLAGS_scene_data;
    return EXIT_FAILURE;
  }

  auto& camera_config = *(scene_config.mutable_scene_data()->mutable_camera());
  if (FLAGS_image_resolution_x > 0) {
    camera_config.set_resolution_x(FLAGS_image_resolution_x);
  }
  if (FLAGS_image_resolution_y > 0) {
    camera_config.set_resolution_y(FLAGS_image_resolution_y);
  }

  if (!FLAGS_splitting_strategy.empty()) {
    if (FLAGS_splitting_strategy == "midpoint") {
      scene_config.mutable_kd_tree_config()
          ->set_splitting_strategy(raytracer::KdTreeConfig::MIDPOINT);
    } else {
      LOG(WARNING) << "Skipping unknown splitting strategy: "
                   << FLAGS_splitting_strategy;
    }
  }

  if (FLAGS_kd_tree_visualization_depth >= 0) {
    // TODO(dinow): Add support for configuring visualization material.
    raytracer::ColorData color;
    color.set_r(0.6);
    color.set_g(0.25);
    color.set_b(0.1);

    raytracer::MaterialData data;
    data.mutable_emission()->CopyFrom(color);
    data.mutable_ambient();
    data.mutable_diffuse();
    data.mutable_specular();
    data.set_refraction_percentage(0.6);
    data.set_refraction_index(1);

    raytracer::KdTreeConfig* kdconfig = scene_config.mutable_kd_tree_config();
    kdconfig->set_visualization_depth(FLAGS_kd_tree_visualization_depth);
    kdconfig->mutable_visualization_material()->CopyFrom(data);
  }

  // Build the scene from the config.
  std::unique_ptr<Scene> scene(Scene::FromConfig(scene_config));

  // Load renderer config from flags.
  RendererConfig renderer_config;
  renderer_config.set_threads(FLAGS_worker_threads);
  renderer_config.set_shadows(FLAGS_shadows);
  renderer_config.set_recursion_depth(FLAGS_recursion_depth);
  renderer_config.set_rays_per_pixel(FLAGS_rays_per_pixel);

  if (!FLAGS_sampler_type.empty()) {
    if (FLAGS_sampler_type == "progressive") {
      renderer_config.set_sampler_type(RendererConfig::PROGRESSIVE);
    } else if (FLAGS_sampler_type == "scanline") {
      renderer_config.set_sampler_type(RendererConfig::SCANLINE);
    } else {
      LOG(WARNING) << "Skipping unknown sampler type: " << FLAGS_sampler_type;
    }
  }

  // Build a renderer from the config.
  std::unique_ptr<Renderer> renderer(Renderer::FromConfig(renderer_config));

  renderer->AddListener(new ProgressListener());
  if (!FLAGS_bmp_file.empty()) {
    renderer->AddListener(new BmpExporter("output/" + FLAGS_bmp_file + ".bmp"));
  }
  if (!FLAGS_ppm_file.empty()) {
    renderer->AddListener(new PpmExporter("output/" + FLAGS_ppm_file + ".ppm"));
  }

  RaytracerWindow* window = NULL;
  if (FLAGS_gui) {
    window = new RaytracerWindow(&argc, argv);
    renderer->AddListener(window);
  }

  // Run the rendering itself on an own thread to allow the UI (if any) to be
  // on the main thread.
  std::thread thread(&Renderer::Render, renderer.get(), scene.get());

  if (window != NULL) {
    // This never returns. That's ok since memory freeing is done after this
    // exits anyway.
    window->MainLoop();
  }

  // Only relevant if there is no GUI.
  thread.join();

  // Free all memory in the various Google libraries.
  google::protobuf::ShutdownProtobufLibrary();
  google::ShutdownGoogleLogging();
  google::ShutDownCommandLineFlags();
  return EXIT_SUCCESS;
}
<commit_msg>Remove todo.<commit_after>/*
 * A command line binary for the ray tracer.
 * Autor: Dino Wernli
 */

#include <fstream>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/text_format.h>
#include <memory>
#include <streambuf>
#include <string>
#include <thread>

#include "listener/bmp_exporter.h"
#include "listener/ppm_exporter.h"
#include "listener/progress_listener.h"
#include "listener/raytracer_window.h"
#include "proto/config/renderer_config.pb.h"
#include "proto/config/scene_config.pb.h"
#include "proto/scene/scene_data.pb.h"
#include "renderer/renderer.h"
#include "scene/scene.h"

using raytracer::RendererConfig;
using raytracer::SceneConfig;

// Renderer config flags.
DEFINE_bool(shadows, true, "Whether or not shadows are rendered");

DEFINE_uint64(recursion_depth, 10, "How deep to evaluate reflective and "
                                   "refractive rays");

DEFINE_uint64(rays_per_pixel, 1, "The number of randomly jittered rays to "
                                 "shoot through each pixel");

DEFINE_bool(use_kd_tree, true, "Whether or not to use a KdTree in the scene");

DEFINE_int32(kd_tree_visualization_depth, -1, "How deep in the tree to "
                                              "visualize splitting planes");

DEFINE_uint64(worker_threads, 8, "Number of rendering worker threads to use");

DEFINE_string(sampler_type, "", "The type of sampler to use. Legal values are "
                                "'scanline' and 'progressive'");

DEFINE_string(splitting_strategy, "", "The strategy to use for splitting in the"
                                      " KdTree. Only has effect if use_kd_tree "
                                      "is true. Legal values are 'midpoint'");

// Camera config flags.
DEFINE_int32(image_resolution_x, -1, "Optional override for the horizontal "
                                      "resolution of the image");

DEFINE_int32(image_resolution_y, -1, "Optional override for the vertical "
                                      "resolution of the image");

// Output flags.
DEFINE_string(bmp_file, "image", "If <file> is passed, a BMP image will be "
                                  "saved at 'output/<file>.bmp'");

DEFINE_string(ppm_file, "", "If <file> is passed, a PPM image will be saved at "
                            "'output/<file>.ppm'");

DEFINE_string(scene_data, "data/scene/quadrics_tori.sd",
                          "A file from which to parse the items in the scene");

DEFINE_bool(gui, false, "Whether or not to start the GLUT front end");

/* General Todos:

TODO(dinow): Add support for building and running binaries and single tests in
             scons. Add multiple targets.
TODO(dinow): Implement surface area heuristics for KdTree splitting
TODO(dinow): Implement adaptive supersampling
TODO(dinow): Add textures, perlin noise, bump maps, skyboxes, path tracing
TODO(dinow): Add possibility to load renderer config from file.
TODO(dinow): Rename proto namespace to "config" or "proto".
TODO(dinow): Put everything else in namespace "raytracer".
TODO(dinow): Implement a webserver.
TODO(dinow): Implement statistics (intersection counting).
TODO(dinow): Remove the default values from the object constructors.
             Leave them only in the protos. Or leave them in both but always
             pass the arguments.
*/

bool LoadSceneData(const std::string& path, raytracer::SceneData* output) {
  std::ifstream stream(path);
  if (!stream.is_open()) {
    return false;
  }
  std::string string((std::istreambuf_iterator<char>(stream)),
                      std::istreambuf_iterator<char>());
  return google::protobuf::TextFormat::ParseFromString(string, output);
}

int main(int argc, char **argv) {
  // LOG(INFO): Always logged.
  // DVLOG(i): Only compiled in if DEBUG flag set.
  //
  // Run <binary name> --logtostderr to see log output.
  // Run <binary name> --logtostderr --v=<i> for DVLOG(j) message for j <= i.
  google::InitGoogleLogging(argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  // Load the configuration from the passed arguments.
  SceneConfig scene_config;
  if (FLAGS_use_kd_tree) {
    scene_config.mutable_kd_tree_config();
  }
  if (FLAGS_scene_data.empty()) {
    LOG(ERROR) << "Failed to load scene data, no file provided";
    return EXIT_FAILURE;
  }
  if (LoadSceneData(FLAGS_scene_data, scene_config.mutable_scene_data())) {
    LOG(INFO) << "Loaded scene data from: " << FLAGS_scene_data;
  } else {
    LOG(ERROR) << "Failed to load scene data from: " << FLAGS_scene_data;
    return EXIT_FAILURE;
  }

  auto& camera_config = *(scene_config.mutable_scene_data()->mutable_camera());
  if (FLAGS_image_resolution_x > 0) {
    camera_config.set_resolution_x(FLAGS_image_resolution_x);
  }
  if (FLAGS_image_resolution_y > 0) {
    camera_config.set_resolution_y(FLAGS_image_resolution_y);
  }

  if (!FLAGS_splitting_strategy.empty()) {
    if (FLAGS_splitting_strategy == "midpoint") {
      scene_config.mutable_kd_tree_config()
          ->set_splitting_strategy(raytracer::KdTreeConfig::MIDPOINT);
    } else {
      LOG(WARNING) << "Skipping unknown splitting strategy: "
                   << FLAGS_splitting_strategy;
    }
  }

  if (FLAGS_kd_tree_visualization_depth >= 0) {
    // TODO(dinow): Add support for configuring visualization material.
    raytracer::ColorData color;
    color.set_r(0.6);
    color.set_g(0.25);
    color.set_b(0.1);

    raytracer::MaterialData data;
    data.mutable_emission()->CopyFrom(color);
    data.mutable_ambient();
    data.mutable_diffuse();
    data.mutable_specular();
    data.set_refraction_percentage(0.6);
    data.set_refraction_index(1);

    raytracer::KdTreeConfig* kdconfig = scene_config.mutable_kd_tree_config();
    kdconfig->set_visualization_depth(FLAGS_kd_tree_visualization_depth);
    kdconfig->mutable_visualization_material()->CopyFrom(data);
  }

  // Build the scene from the config.
  std::unique_ptr<Scene> scene(Scene::FromConfig(scene_config));

  // Load renderer config from flags.
  RendererConfig renderer_config;
  renderer_config.set_threads(FLAGS_worker_threads);
  renderer_config.set_shadows(FLAGS_shadows);
  renderer_config.set_recursion_depth(FLAGS_recursion_depth);
  renderer_config.set_rays_per_pixel(FLAGS_rays_per_pixel);

  if (!FLAGS_sampler_type.empty()) {
    if (FLAGS_sampler_type == "progressive") {
      renderer_config.set_sampler_type(RendererConfig::PROGRESSIVE);
    } else if (FLAGS_sampler_type == "scanline") {
      renderer_config.set_sampler_type(RendererConfig::SCANLINE);
    } else {
      LOG(WARNING) << "Skipping unknown sampler type: " << FLAGS_sampler_type;
    }
  }

  // Build a renderer from the config.
  std::unique_ptr<Renderer> renderer(Renderer::FromConfig(renderer_config));

  renderer->AddListener(new ProgressListener());
  if (!FLAGS_bmp_file.empty()) {
    renderer->AddListener(new BmpExporter("output/" + FLAGS_bmp_file + ".bmp"));
  }
  if (!FLAGS_ppm_file.empty()) {
    renderer->AddListener(new PpmExporter("output/" + FLAGS_ppm_file + ".ppm"));
  }

  RaytracerWindow* window = NULL;
  if (FLAGS_gui) {
    window = new RaytracerWindow(&argc, argv);
    renderer->AddListener(window);
  }

  // Run the rendering itself on an own thread to allow the UI (if any) to be
  // on the main thread.
  std::thread thread(&Renderer::Render, renderer.get(), scene.get());

  if (window != NULL) {
    // This never returns. That's ok since memory freeing is done after this
    // exits anyway.
    window->MainLoop();
  }

  // Only relevant if there is no GUI.
  thread.join();

  // Free all memory in the various Google libraries.
  google::protobuf::ShutdownProtobufLibrary();
  google::ShutdownGoogleLogging();
  google::ShutDownCommandLineFlags();
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include "gtest/gtest.h"
#include "test/gtest_supp.h"

#include <iostream>
#include <string>
#include <algorithm>

#include "EasyCL.h"

using namespace std;

namespace testCopyLocal{

CLKernel *makeKernel( EasyCL *cl );

TEST( testCopyLocal, basic ) {
    EasyCL *cl = EasyCL::createForFirstGpuOtherwiseCpu();

    float a[] = { 1,2,3,4,
                  5,6,7,8,
                  9,10,11,12 };
    float b[16];
    memset(b, 0, sizeof(float)*16);

    CLKernel *kernel = makeKernel( cl );
    kernel->in( 12, a )->out( 16, b )->in( 12 );
    kernel->localFloats( 12 );
    kernel->run_1d(12,12);
    cl->finish();
    for( int i = 0; i < 3; i++ ) {
        for( int j = 0; j < 4; j++ ) {
            cout << b[i*4+j] << " ";
            EXPECT_EQ( i * 4 + j + 1, b[i*4+j] );
        }
        cout << endl;
    }
    cout << endl;
    for( int i = 12; i < 16; i++ ) {
        cout << b[i] << " ";
        EXPECT_FLOAT_NEAR( 0, b[i] );
    }
    cout << endl;

    delete kernel;
    delete cl;
}

CLKernel *makeKernel( EasyCL *cl ) {
    CLKernel *kernel = 0;
    // [[[cog
    // import stringify
    // stringify.write_kernel2( "kernel", "test/testCopyLocal.cl", "run", '""' )
    // ]]]
    // generated using cog, from test/testCopyLocal.cl:
    const char * kernelSource =
    "// Copyright Hugh Perkins 2015 hughperkins at gmail\n"
    "//\n"
    "// This Source Code Form is subject to the terms of the Mozilla Public License,\n"
    "// v. 2.0. If a copy of the MPL was not distributed with this file, You can\n"
    "// obtain one at http://mozilla.org/MPL/2.0/.\n"
    "\n"
    "// including cl/copyBlock.cl:\n"
    "// Copyright Hugh Perkins 2015 hughperkins at gmail\n"
    "//\n"
    "// This Source Code Form is subject to the terms of the Mozilla Public License,\n"
    "// v. 2.0. If a copy of the MPL was not distributed with this file, You can\n"
    "// obtain one at http://mozilla.org/MPL/2.0/.\n"
    "\n"
    "int posToRow( int pos ) {\n"
    "    return ( pos >> 10 ) & ( (1<<10)-1);\n"
    "//    return 53\n"
    "}\n"
    "int posToCol( int pos ) {\n"
    "    return pos & ((1<<10)-1);\n"
    "  //  return 67;\n"
    "    //return ((1<<11)-1);\n"
    "}\n"
    "int rowColToPos( int row, int col ) {\n"
    "    return ( row << 10 ) | col;\n"
    "}\n"
    "int linearIdToPos( int linearId, int base ) {\n"
    "    return rowColToPos( ( linearId / base ), ( linearId % base )  );\n"
    "}\n"
    "int posToOffset( int pos, int rowLength ) {\n"
    "    return posToRow(pos) * rowLength + posToCol(pos);\n"
    "}\n"
    "\n"
    "// assumes that the block will fit exactly into the target\n"
    "void copyBlock( local float *target, global float const *source,\n"
    "    const int sourceSize, const int blockStart, const int blockSize ) {\n"
    "    const int totalLinearSize = posToRow( blockSize ) * posToCol( blockSize );\n"
    "    const int numLoops = ( totalLinearSize + get_local_size(0) - 1 ) / get_local_size(0);\n"
    "    for( int loop = 0; loop < numLoops; loop++ ) {\n"
    "        const int offset = get_local_id(0) + loop * get_local_size(0);\n"
    "        if( offset < totalLinearSize ) {\n"
    "            const int offsetAsPos = linearIdToPos( offset, posToCol( blockSize ) );\n"
    "            target[ offset ] = source[ posToOffset( blockStart + offsetAsPos, posToCol( sourceSize ) ) ];\n"
    "        }\n"
    "    }\n"
    "}\n"
    "\n"
    "\n"
    "\n"
    "// including cl/ids.cl:\n"
    "// Copyright Hugh Perkins 2015 hughperkins at gmail\n"
    "//\n"
    "// This Source Code Form is subject to the terms of the Mozilla Public License,\n"
    "// v. 2.0. If a copy of the MPL was not distributed with this file, You can\n"
    "// obtain one at http://mozilla.org/MPL/2.0/.\n"
    "\n"
    "#define globalId ( get_global_id(0) )\n"
    "#define localId ( get_local_id(0)  )\n"
    "#define workgroupId ( get_group_id(0) )\n"
    "#define workgroupSize ( get_local_size(0) )\n"
    "\n"
    "\n"
    "\n"
    "// including cl/copyLocal.cl:\n"
    "// Copyright Hugh Perkins 2015 hughperkins at gmail\n"
    "//\n"
    "// This Source Code Form is subject to the terms of the Mozilla Public License,\n"
    "// v. 2.0. If a copy of the MPL was not distributed with this file, You can\n"
    "// obtain one at http://mozilla.org/MPL/2.0/.\n"
    "\n"
    "void copyLocal( local float *target, global float const *source, int N ) {\n"
    "    int numLoops = ( N + get_local_size(0) - 1 ) / get_local_size(0);\n"
    "    for( int loop = 0; loop < numLoops; loop++ ) {\n"
    "        int offset = loop * get_local_size(0) + get_local_id(0);\n"
    "        if( offset < N ) {\n"
    "            target[offset] = source[offset];\n"
    "        }\n"
    "    }\n"
    "}\n"
    "\n"
    "void copyGlobal( global float *target, local float const *source, int N ) {\n"
    "    int numLoops = ( N + get_local_size(0) - 1 ) / get_local_size(0);\n"
    "    for( int loop = 0; loop < numLoops; loop++ ) {\n"
    "        int offset = loop * get_local_size(0) + get_local_id(0);\n"
    "        if( offset < N ) {\n"
    "            target[offset] = source[offset];\n"
    "        }\n"
    "    }\n"
    "}\n"
    "\n"
    "\n"
    "\n"
    "kernel void run( global const float *source, global float *destination, int N,\n"
    "    local float *localBuffer ) {\n"
    "    copyLocal( localBuffer, source, N );\n"
    "    barrier(CLK_LOCAL_MEM_FENCE);\n"
    "    copyGlobal( destination, localBuffer, N );\n"
    "}\n"
    "\n"
    "";
    kernel = cl->buildKernelFromString( kernelSource, "run", "", "test/testCopyLocal.cl" );
    // [[[end]]]

    return kernel;
}

}

<commit_msg>fix testcopylocal test<commit_after>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

#include "gtest/gtest.h"
#include "test/gtest_supp.h"

#include <iostream>
#include <string>
#include <algorithm>

#include "EasyCL.h"

using namespace std;

namespace testCopyLocal{

CLKernel *makeKernel( EasyCL *cl );

TEST( testCopyLocal, basic ) {
    EasyCL *cl = EasyCL::createForFirstGpuOtherwiseCpu();

    float a[] = { 1,2,3,4,
                  5,6,7,8,
                  9,10,11,12 };
    float b[16];
    memset(b, 0, sizeof(float)*16);
    for( int i = 12; i < 16; i++ ) {
        cout << b[i] << " ";
        EXPECT_FLOAT_NEAR( 0, b[i] );
    }
    cout << endl;

    CLKernel *kernel = makeKernel( cl );
    kernel->in( 12, a )->inout( 16, b )->in( 12 );
    kernel->localFloats( 12 );
    kernel->run_1d(12,12);
    cl->finish();
    for( int i = 0; i < 3; i++ ) {
        for( int j = 0; j < 4; j++ ) {
            cout << b[i*4+j] << " ";
            EXPECT_EQ( i * 4 + j + 1, b[i*4+j] );
        }
        cout << endl;
    }
    cout << endl;
    for( int i = 12; i < 16; i++ ) {
        cout << b[i] << " ";
        EXPECT_FLOAT_NEAR( 0, b[i] );
    }
    cout << endl;

    delete kernel;
    delete cl;
}

CLKernel *makeKernel( EasyCL *cl ) {
    CLKernel *kernel = 0;
    // [[[cog
    // import stringify
    // stringify.write_kernel2( "kernel", "test/testCopyLocal.cl", "run", '""' )
    // ]]]
    // generated using cog, from test/testCopyLocal.cl:
    const char * kernelSource =
    "// Copyright Hugh Perkins 2015 hughperkins at gmail\n"
    "//\n"
    "// This Source Code Form is subject to the terms of the Mozilla Public License,\n"
    "// v. 2.0. If a copy of the MPL was not distributed with this file, You can\n"
    "// obtain one at http://mozilla.org/MPL/2.0/.\n"
    "\n"
    "// including cl/copyBlock.cl:\n"
    "// Copyright Hugh Perkins 2015 hughperkins at gmail\n"
    "//\n"
    "// This Source Code Form is subject to the terms of the Mozilla Public License,\n"
    "// v. 2.0. If a copy of the MPL was not distributed with this file, You can\n"
    "// obtain one at http://mozilla.org/MPL/2.0/.\n"
    "\n"
    "int posToRow( int pos ) {\n"
    "    return ( pos >> 10 ) & ( (1<<10)-1);\n"
    "//    return 53\n"
    "}\n"
    "int posToCol( int pos ) {\n"
    "    return pos & ((1<<10)-1);\n"
    "  //  return 67;\n"
    "    //return ((1<<11)-1);\n"
    "}\n"
    "int rowColToPos( int row, int col ) {\n"
    "    return ( row << 10 ) | col;\n"
    "}\n"
    "int linearIdToPos( int linearId, int base ) {\n"
    "    return rowColToPos( ( linearId / base ), ( linearId % base )  );\n"
    "}\n"
    "int posToOffset( int pos, int rowLength ) {\n"
    "    return posToRow(pos) * rowLength + posToCol(pos);\n"
    "}\n"
    "\n"
    "// assumes that the block will fit exactly into the target\n"
    "void copyBlock( local float *target, global float const *source,\n"
    "    const int sourceSize, const int blockStart, const int blockSize ) {\n"
    "    const int totalLinearSize = posToRow( blockSize ) * posToCol( blockSize );\n"
    "    const int numLoops = ( totalLinearSize + get_local_size(0) - 1 ) / get_local_size(0);\n"
    "    for( int loop = 0; loop < numLoops; loop++ ) {\n"
    "        const int offset = get_local_id(0) + loop * get_local_size(0);\n"
    "        if( offset < totalLinearSize ) {\n"
    "            const int offsetAsPos = linearIdToPos( offset, posToCol( blockSize ) );\n"
    "            target[ offset ] = source[ posToOffset( blockStart + offsetAsPos, posToCol( sourceSize ) ) ];\n"
    "        }\n"
    "    }\n"
    "}\n"
    "\n"
    "\n"
    "\n"
    "// including cl/ids.cl:\n"
    "// Copyright Hugh Perkins 2015 hughperkins at gmail\n"
    "//\n"
    "// This Source Code Form is subject to the terms of the Mozilla Public License,\n"
    "// v. 2.0. If a copy of the MPL was not distributed with this file, You can\n"
    "// obtain one at http://mozilla.org/MPL/2.0/.\n"
    "\n"
    "#define globalId ( get_global_id(0) )\n"
    "#define localId ( get_local_id(0)  )\n"
    "#define workgroupId ( get_group_id(0) )\n"
    "#define workgroupSize ( get_local_size(0) )\n"
    "\n"
    "\n"
    "\n"
    "// including cl/copyLocal.cl:\n"
    "// Copyright Hugh Perkins 2015 hughperkins at gmail\n"
    "//\n"
    "// This Source Code Form is subject to the terms of the Mozilla Public License,\n"
    "// v. 2.0. If a copy of the MPL was not distributed with this file, You can\n"
    "// obtain one at http://mozilla.org/MPL/2.0/.\n"
    "\n"
    "void copyLocal( local float *target, global float const *source, int N ) {\n"
    "    int numLoops = ( N + get_local_size(0) - 1 ) / get_local_size(0);\n"
    "    for( int loop = 0; loop < numLoops; loop++ ) {\n"
    "        int offset = loop * get_local_size(0) + get_local_id(0);\n"
    "        if( offset < N ) {\n"
    "            target[offset] = source[offset];\n"
    "        }\n"
    "    }\n"
    "}\n"
    "\n"
    "void copyGlobal( global float *target, local float const *source, int N ) {\n"
    "    int numLoops = ( N + get_local_size(0) - 1 ) / get_local_size(0);\n"
    "    for( int loop = 0; loop < numLoops; loop++ ) {\n"
    "        int offset = loop * get_local_size(0) + get_local_id(0);\n"
    "        if( offset < N ) {\n"
    "            target[offset] = source[offset];\n"
    "        }\n"
    "    }\n"
    "}\n"
    "\n"
    "\n"
    "\n"
    "kernel void run( global const float *source, global float *destination, int N,\n"
    "    local float *localBuffer ) {\n"
    "    copyLocal( localBuffer, source, N );\n"
    "    barrier(CLK_LOCAL_MEM_FENCE);\n"
    "    copyGlobal( destination, localBuffer, N );\n"
    "}\n"
    "\n"
    "";
    kernel = cl->buildKernelFromString( kernelSource, "run", "", "test/testCopyLocal.cl" );
    // [[[end]]]

    return kernel;
}

}

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief map the environment to javascript
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// heavily inspired by
/// https://github.com/joyent/node/blob/master/src/node.cc
////////////////////////////////////////////////////////////////////////////////

#include "Basics/Common.h"
#include "v8-utils.h"

#ifdef _WIN32
#include "Basics/win-utils.h"
#else
#ifdef __APPLE__
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#elif !defined(_MSC_VER)
extern char **environ;
#endif
#endif

static void EnvGetter(v8::Local<v8::String> property,
                      const v8::PropertyCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
  v8::String::Utf8Value const key(property);
#ifndef _WIN32
  const char* val = getenv(*key);
  if (val) {
    TRI_V8_RETURN_STRING(val);
  }
#else  // _WIN32
  WCHAR buffer[32767];  // The maximum size allowed for environment variables.
  DWORD result = GetEnvironmentVariableW(reinterpret_cast<const WCHAR*>(*key),
                                         buffer,
                                         sizeof(buffer));
  // If result >= sizeof buffer the buffer was too small. That should never
  // happen. If result == 0 and result != ERROR_SUCCESS the variable was not
  // not found.
  if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
      result < sizeof(buffer)) {
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer);
    auto rc = TRI_V8_STRING_UTF16(two_byte_buffer, result);
    TRI_V8_RETURN(rc);
  }
#endif
  // Not found.  Fetch from prototype.
  TRI_V8_RETURN(args.Data().As<v8::Object>()->Get(property));
}

static void EnvSetter(v8::Local<v8::String> property,
                      v8::Local<v8::Value> value,
                      const v8::PropertyCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
#ifndef _WIN32
  v8::String::Utf8Value key(property);
  v8::String::Utf8Value val(value);
  setenv(*key, *val, 1);
#else  // _WIN32
  v8::String::Value key(property);
  v8::String::Value val(value);
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
  // Environment variables that start with '=' are read-only.
  if (key_ptr[0] != L'=') {
    SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
  }
#endif
  // Whether it worked or not, always return rval.
  TRI_V8_RETURN(value);
}

static void EnvQuery(v8::Local<v8::String> property,
                     const v8::PropertyCallbackInfo<v8::Integer>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
  int32_t rc = -1;  // Not found unless proven otherwise.
#ifndef _WIN32
  v8::String::Utf8Value key(property);
  if (getenv(*key))
    rc = 0;
#else  // _WIN32
  v8::String::Utf8Value key(property);
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
  if (GetEnvironmentVariableW(key_ptr, NULL, 0) > 0 ||
      GetLastError() == ERROR_SUCCESS) {
    rc = 0;
    if (key_ptr[0] == L'=') {
      // Environment variables that start with '=' are hidden and read-only.
      rc = static_cast<int32_t>(v8::ReadOnly) |
           static_cast<int32_t>(v8::DontDelete) |
           static_cast<int32_t>(v8::DontEnum);
    }
  }
#endif
  if (rc != -1)
    TRI_V8_RETURN(rc);
}

static void EnvDeleter(v8::Local<v8::String> property,
                       const v8::PropertyCallbackInfo<v8::Boolean>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
  bool rc = true;
  v8::String::Utf8Value key(property);
#ifndef _WIN32
  rc = getenv(*key) != NULL;
  if (rc)
    unsetenv(*key);
#else
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
  if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, NULL)) {
    // Deletion failed. Return true if the key wasn't there in the first place,
    // false if it is still there.
    rc = GetEnvironmentVariableW(key_ptr, NULL, NULL) == 0 &&
         GetLastError() != ERROR_SUCCESS;
  }
#endif
  if (rc) {
    TRI_V8_RETURN_TRUE();
  }
  else {
    TRI_V8_RETURN_FALSE();
  }
}

static void EnvEnumerator(const v8::PropertyCallbackInfo<v8::Array>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
#ifndef _WIN32
  int size = 0;
  while (environ[size])
    size++;

  v8::Local<v8::Array> envarr = v8::Array::New(isolate, size);

  for (int i = 0; i < size; ++i) {
    const char* var = environ[i];
    const char* s = strchr(var, '=');
    const int length = s ? s - var : strlen(var);
    v8::Local<v8::String> name = TRI_V8_PAIR_STRING(var, length);
    envarr->Set(i, name);
  }
#else  // _WIN32
  WCHAR* environment = GetEnvironmentStringsW();
  if (environment == NULL)
    return;  // This should not happen.
  v8::Local<v8::Array> envarr = v8::Array::New(isolate);
  WCHAR* p = environment;
  int i = 0;
  while (*p != NULL) {
    WCHAR *s;
    if (*p == L'=') {
      // If the key starts with '=' it is a hidden environment variable.
      p += wcslen(p) + 1;
      continue;
    } else {
      s = wcschr(p, L'=');
    }
    if (!s) {
      s = p + wcslen(p);
    }
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(p);
    const size_t two_byte_buffer_len = s - p;
    auto value = TRI_V8_STRING_UTF16(two_byte_buffer, (int)two_byte_buffer_len);
    envarr->Set(i++, value);
    p = s + wcslen(s) + 1;
  }
  FreeEnvironmentStringsW(environment);
#endif

  TRI_V8_RETURN(envarr);
}

// -----------------------------------------------------------------------------
// --SECTION--                                             module initialisation
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief stores the V8 utils functions inside the global variable
////////////////////////////////////////////////////////////////////////////////

void TRI_InitV8Env (v8::Isolate* isolate,
                    v8::Handle<v8::Context> context,
                    std::string const& startupPath,
                    std::string const& modules) {
  v8::HandleScope scope(isolate);
  TRI_v8_global_t* v8g = TRI_GetV8Globals(isolate);

  v8::Handle<v8::ObjectTemplate> rt;
  v8::Handle<v8::FunctionTemplate> ft;

  ft = v8::FunctionTemplate::New(isolate);
  ft->SetClassName(TRI_V8_ASCII_STRING("ENV"));

  rt = ft->InstanceTemplate();
  // rt->SetInternalFieldCount(3);

  rt->SetNamedPropertyHandler(EnvGetter,
                              EnvSetter,
                              EnvQuery,
                              EnvDeleter,
                              EnvEnumerator,
                              v8::Object::New(isolate));
  v8g->EnvTempl.Reset(isolate, rt);
  TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("ENV"), ft->GetFunction());
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>Windows: String::Value is the way to get twobyte-strings.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief map the environment to javascript
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// heavily inspired by
/// https://github.com/joyent/node/blob/master/src/node.cc
////////////////////////////////////////////////////////////////////////////////

#include "Basics/Common.h"
#include "v8-utils.h"

#ifdef _WIN32
#include "Basics/win-utils.h"
#else
#ifdef __APPLE__
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#elif !defined(_MSC_VER)
extern char **environ;
#endif
#endif

static void EnvGetter(v8::Local<v8::String> property,
                      const v8::PropertyCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
#ifndef _WIN32
  v8::String::Utf8Value const key(property);
  const char* val = getenv(*key);
  if (val) {
    TRI_V8_RETURN_STRING(val);
  }
#else  // _WIN32
  v8::String::Value key(property);
  WCHAR buffer[32767];  // The maximum size allowed for environment variables.
  DWORD result = GetEnvironmentVariableW(reinterpret_cast<const WCHAR*>(*key),
                                         buffer,
                                         sizeof(buffer));

  // ERROR_ENVVAR_NOT_FOUND is possibly returned.
  // If result >= sizeof buffer the buffer was too small. That should never
  // happen. If result == 0 and result != ERROR_SUCCESS the variable was not
  // not found.
  if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
      result < sizeof(buffer)) {
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer);
    TRI_V8_RETURN(TRI_V8_STRING_UTF16(two_byte_buffer, result));
  }
#endif
  // Not found.  Fetch from prototype.
  TRI_V8_RETURN(args.Data().As<v8::Object>()->Get(property));
}

static void EnvSetter(v8::Local<v8::String> property,
                      v8::Local<v8::Value> value,
                      const v8::PropertyCallbackInfo<v8::Value>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
#ifndef _WIN32
  v8::String::Utf8Value key(property);
  v8::String::Utf8Value val(value);
  setenv(*key, *val, 1);
#else  // _WIN32
  v8::String::Value key(property);
  v8::String::Value val(value);
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
  // Environment variables that start with '=' are read-only.
  if (key_ptr[0] != L'=') {
    SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
  }
#endif
  // Whether it worked or not, always return rval.
  TRI_V8_RETURN(value);
}

static void EnvQuery(v8::Local<v8::String> property,
                     const v8::PropertyCallbackInfo<v8::Integer>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
  int32_t rc = -1;  // Not found unless proven otherwise.
#ifndef _WIN32
  v8::String::Utf8Value key(property);
  if (getenv(*key))
    rc = 0;
#else  // _WIN32
  v8::String::Value key(property);
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
  SetLastError(ERROR_SUCCESS);

  if (GetEnvironmentVariableW(key_ptr, NULL, 0) > 0 ||
      GetLastError() == ERROR_SUCCESS) {
    rc = 0;
    if (key_ptr[0] == L'=') {
      // Environment variables that start with '=' are hidden and read-only.
      rc = static_cast<int32_t>(v8::ReadOnly) |
           static_cast<int32_t>(v8::DontDelete) |
           static_cast<int32_t>(v8::DontEnum);
    }
  }
#endif
  if (rc != -1)
    TRI_V8_RETURN(rc);
}

static void EnvDeleter(v8::Local<v8::String> property,
                       const v8::PropertyCallbackInfo<v8::Boolean>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
  bool rc = true;
#ifndef _WIN32
  v8::String::Utf8Value key(property);
  rc = getenv(*key) != NULL;
  if (rc)
    unsetenv(*key);
#else
  v8::String::Value key(property);
  WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
  if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, NULL)) {
    // Deletion failed. Return true if the key wasn't there in the first place,
    // false if it is still there.
    rc = GetEnvironmentVariableW(key_ptr, NULL, NULL) == 0 &&
         GetLastError() != ERROR_SUCCESS;
  }
#endif
  if (rc) {
    TRI_V8_RETURN_TRUE();
  }
  else {
    TRI_V8_RETURN_FALSE();
  }
}

static void EnvEnumerator(const v8::PropertyCallbackInfo<v8::Array>& args) {
  v8::Isolate* isolate = args.GetIsolate();
  v8::HandleScope scope(isolate);
#ifndef _WIN32
  int size = 0;
  while (environ[size])
    size++;

  v8::Local<v8::Array> envarr = v8::Array::New(isolate, size);

  for (int i = 0; i < size; ++i) {
    const char* var = environ[i];
    const char* s = strchr(var, '=');
    const int length = s ? s - var : strlen(var);
    v8::Local<v8::String> name = TRI_V8_PAIR_STRING(var, length);
    envarr->Set(i, name);
  }
#else  // _WIN32
  WCHAR* environment = GetEnvironmentStringsW();
  if (environment == NULL)
    return;  // This should not happen.
  v8::Local<v8::Array> envarr = v8::Array::New(isolate);
  WCHAR* p = environment;
  int i = 0;
  while (*p != NULL) {
    WCHAR *s;
    if (*p == L'=') {
      // If the key starts with '=' it is a hidden environment variable.
      p += wcslen(p) + 1;
      continue;
    } else {
      s = wcschr(p, L'=');
    }
    if (!s) {
      s = p + wcslen(p);
    }
    const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(p);
    const size_t two_byte_buffer_len = s - p;
    auto value = TRI_V8_STRING_UTF16(two_byte_buffer, (int)two_byte_buffer_len);

    envarr->Set(i, value);
    p = s + wcslen(s) + 1;
    i++;
  }
  FreeEnvironmentStringsW(environment);
#endif

  TRI_V8_RETURN(envarr);
}

// -----------------------------------------------------------------------------
// --SECTION--                                             module initialisation
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief stores the V8 utils functions inside the global variable
////////////////////////////////////////////////////////////////////////////////

void TRI_InitV8Env (v8::Isolate* isolate,
                    v8::Handle<v8::Context> context,
                    std::string const& startupPath,
                    std::string const& modules) {
  v8::HandleScope scope(isolate);
  TRI_v8_global_t* v8g = TRI_GetV8Globals(isolate);

  v8::Handle<v8::ObjectTemplate> rt;
  v8::Handle<v8::FunctionTemplate> ft;

  ft = v8::FunctionTemplate::New(isolate);
  ft->SetClassName(TRI_V8_ASCII_STRING("ENV"));

  rt = ft->InstanceTemplate();
  // rt->SetInternalFieldCount(3);

  rt->SetNamedPropertyHandler(EnvGetter,
                              EnvSetter,
                              EnvQuery,
                              EnvDeleter,
                              EnvEnumerator,
                              v8::Object::New(isolate));
  v8g->EnvTempl.Reset(isolate, rt);
  TRI_AddGlobalFunctionVocbase(isolate, context, TRI_V8_ASCII_STRING("ENV"), ft->GetFunction());
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before>//===- Dominators.cpp - Dominator Calculation -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements simple dominator construction algorithms for finding
// forward dominators.  Postdominators are available in libanalysis, but are not
// included in libvmcore, because it's not needed.  Forward dominators are
// needed to support the Verifier pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Dominators.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/DominatorInternals.h"
#include "llvm/Instructions.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include <algorithm>
using namespace llvm;

// Always verify dominfo if expensive checking is enabled.
#ifdef XDEBUG
bool VerifyDomInfo = true;
#else
bool VerifyDomInfo = false;
#endif
static cl::opt<bool,true>
VerifyDomInfoX("verify-dom-info", cl::location(VerifyDomInfo),
               cl::desc("Verify dominator info (time consuming)"));

//===----------------------------------------------------------------------===//
//  DominatorTree Implementation
//===----------------------------------------------------------------------===//
//
// Provide public access to DominatorTree information.  Implementation details
// can be found in DominatorCalculation.h.
//
//===----------------------------------------------------------------------===//

TEMPLATE_INSTANTIATION(class llvm::DomTreeNodeBase<BasicBlock>);
TEMPLATE_INSTANTIATION(class llvm::DominatorTreeBase<BasicBlock>);

char DominatorTree::ID = 0;
static RegisterPass<DominatorTree>
E("domtree", "Dominator Tree Construction", true, true);

bool DominatorTree::runOnFunction(Function &F) {
  DT->recalculate(F);
  return false;
}

void DominatorTree::verifyAnalysis() const {
  if (!VerifyDomInfo) return;

  Function &F = *getRoot()->getParent();

  DominatorTree OtherDT;
  OtherDT.getBase().recalculate(F);
  assert(!compare(OtherDT) && "Invalid DominatorTree info!");
}

void DominatorTree::print(raw_ostream &OS, const Module *) const {
  DT->print(OS);
}

// dominates - Return true if A dominates a use in B. This performs the
// special checks necessary if A and B are in the same basic block.
bool DominatorTree::dominates(const Instruction *A, const Instruction *B) const{
  const BasicBlock *BBA = A->getParent(), *BBB = B->getParent();

  // If A is an invoke instruction, its value is only available in this normal
  // successor block.
  if (const InvokeInst *II = dyn_cast<InvokeInst>(A))
    BBA = II->getNormalDest();

  if (BBA != BBB) return dominates(BBA, BBB);

  // It is not possible to determine dominance between two PHI nodes
  // based on their ordering.
  if (isa<PHINode>(A) && isa<PHINode>(B))
    return false;

  // Loop through the basic block until we find A or B.
  BasicBlock::const_iterator I = BBA->begin();
  for (; &*I != A && &*I != B; ++I)
    /*empty*/;

  return &*I == A;
}

//===----------------------------------------------------------------------===//
//  DominanceFrontier Implementation
//===----------------------------------------------------------------------===//

char DominanceFrontier::ID = 0;
static RegisterPass<DominanceFrontier>
G("domfrontier", "Dominance Frontier Construction", true, true);

void DominanceFrontier::verifyAnalysis() const {
  if (!VerifyDomInfo) return;

  DominatorTree &DT = getAnalysis<DominatorTree>();

  DominanceFrontier OtherDF;
  const std::vector<BasicBlock*> &DTRoots = DT.getRoots();
  OtherDF.calculate(DT, DT.getNode(DTRoots[0]));
  assert(!compare(OtherDF) && "Invalid DominanceFrontier info!");
}

// NewBB is split and now it has one successor. Update dominace frontier to
// reflect this change.
void DominanceFrontier::splitBlock(BasicBlock *NewBB) {
  assert(NewBB->getTerminator()->getNumSuccessors() == 1
         && "NewBB should have a single successor!");
  BasicBlock *NewBBSucc = NewBB->getTerminator()->getSuccessor(0);

  SmallVector<BasicBlock*, 8> PredBlocks;
  for (pred_iterator PI = pred_begin(NewBB), PE = pred_end(NewBB);
       PI != PE; ++PI)
      PredBlocks.push_back(*PI);

  if (PredBlocks.empty())
    // If NewBB does not have any predecessors then it is a entry block.
    // In this case, NewBB and its successor NewBBSucc dominates all
    // other blocks.
    return;

  // NewBBSucc inherits original NewBB frontier.
  DominanceFrontier::iterator NewBBI = find(NewBB);
  if (NewBBI != end()) {
    DominanceFrontier::DomSetType NewBBSet = NewBBI->second;
    DominanceFrontier::DomSetType NewBBSuccSet;
    NewBBSuccSet.insert(NewBBSet.begin(), NewBBSet.end());
    addBasicBlock(NewBBSucc, NewBBSuccSet);
  }

  // If NewBB dominates NewBBSucc, then DF(NewBB) is now going to be the
  // DF(PredBlocks[0]) without the stuff that the new block does not dominate
  // a predecessor of.
  DominatorTree &DT = getAnalysis<DominatorTree>();
  if (DT.dominates(NewBB, NewBBSucc)) {
    DominanceFrontier::iterator DFI = find(PredBlocks[0]);
    if (DFI != end()) {
      DominanceFrontier::DomSetType Set = DFI->second;
      // Filter out stuff in Set that we do not dominate a predecessor of.
      for (DominanceFrontier::DomSetType::iterator SetI = Set.begin(),
             E = Set.end(); SetI != E;) {
        bool DominatesPred = false;
        for (pred_iterator PI = pred_begin(*SetI), E = pred_end(*SetI);
             PI != E; ++PI)
          if (DT.dominates(NewBB, *PI))
            DominatesPred = true;
        if (!DominatesPred)
          Set.erase(SetI++);
        else
          ++SetI;
      }

      if (NewBBI != end()) {
        for (DominanceFrontier::DomSetType::iterator SetI = Set.begin(),
               E = Set.end(); SetI != E; ++SetI) {
          BasicBlock *SB = *SetI;
          addToFrontier(NewBBI, SB);
        }
      } else
        addBasicBlock(NewBB, Set);
    }

  } else {
    // DF(NewBB) is {NewBBSucc} because NewBB does not strictly dominate
    // NewBBSucc, but it does dominate itself (and there is an edge (NewBB ->
    // NewBBSucc)).  NewBBSucc is the single successor of NewBB.
    DominanceFrontier::DomSetType NewDFSet;
    NewDFSet.insert(NewBBSucc);
    addBasicBlock(NewBB, NewDFSet);
  }

  // Now we must loop over all of the dominance frontiers in the function,
  // replacing occurrences of NewBBSucc with NewBB in some cases.  All
  // blocks that dominate a block in PredBlocks and contained NewBBSucc in
  // their dominance frontier must be updated to contain NewBB instead.
  //
  for (Function::iterator FI = NewBB->getParent()->begin(),
         FE = NewBB->getParent()->end(); FI != FE; ++FI) {
    DominanceFrontier::iterator DFI = find(FI);
    if (DFI == end()) continue;  // unreachable block.

    // Only consider nodes that have NewBBSucc in their dominator frontier.
    if (!DFI->second.count(NewBBSucc)) continue;

    // Verify whether this block dominates a block in predblocks.  If not, do
    // not update it.
    bool BlockDominatesAny = false;
    for (SmallVectorImpl<BasicBlock*>::const_iterator BI = PredBlocks.begin(),
           BE = PredBlocks.end(); BI != BE; ++BI) {
      if (DT.dominates(FI, *BI)) {
        BlockDominatesAny = true;
        break;
      }
    }

    // If NewBBSucc should not stay in our dominator frontier, remove it.
    // We remove it unless there is a predecessor of NewBBSucc that we
    // dominate, but we don't strictly dominate NewBBSucc.
    bool ShouldRemove = true;
    if ((BasicBlock*)FI == NewBBSucc || !DT.dominates(FI, NewBBSucc)) {
      // Okay, we know that PredDom does not strictly dominate NewBBSucc.
      // Check to see if it dominates any predecessors of NewBBSucc.
      for (pred_iterator PI = pred_begin(NewBBSucc),
           E = pred_end(NewBBSucc); PI != E; ++PI)
        if (DT.dominates(FI, *PI)) {
          ShouldRemove = false;
          break;
        }
    }

    if (ShouldRemove)
      removeFromFrontier(DFI, NewBBSucc);
    if (BlockDominatesAny && (&*FI == NewBB || !DT.dominates(FI, NewBB)))
      addToFrontier(DFI, NewBB);
  }
}

namespace {
  class DFCalculateWorkObject {
  public:
    DFCalculateWorkObject(BasicBlock *B, BasicBlock *P,
                          const DomTreeNode *N,
                          const DomTreeNode *PN)
    : currentBB(B), parentBB(P), Node(N), parentNode(PN) {}
    BasicBlock *currentBB;
    BasicBlock *parentBB;
    const DomTreeNode *Node;
    const DomTreeNode *parentNode;
  };
}

const DominanceFrontier::DomSetType &
DominanceFrontier::calculate(const DominatorTree &DT,
                             const DomTreeNode *Node) {
  BasicBlock *BB = Node->getBlock();
  DomSetType *Result = NULL;

  std::vector<DFCalculateWorkObject> workList;
  SmallPtrSet<BasicBlock *, 32> visited;

  workList.push_back(DFCalculateWorkObject(BB, NULL, Node, NULL));
  do {
    DFCalculateWorkObject *currentW = &workList.back();
    assert (currentW && "Missing work object.");

    BasicBlock *currentBB = currentW->currentBB;
    BasicBlock *parentBB = currentW->parentBB;
    const DomTreeNode *currentNode = currentW->Node;
    const DomTreeNode *parentNode = currentW->parentNode;
    assert (currentBB && "Invalid work object. Missing current Basic Block");
    assert (currentNode && "Invalid work object. Missing current Node");
    DomSetType &S = Frontiers[currentBB];

    // Visit each block only once.
    if (visited.count(currentBB) == 0) {
      visited.insert(currentBB);

      // Loop over CFG successors to calculate DFlocal[currentNode]
      for (succ_iterator SI = succ_begin(currentBB), SE = succ_end(currentBB);
           SI != SE; ++SI) {
        // Does Node immediately dominate this successor?
        if (DT[*SI]->getIDom() != currentNode)
          S.insert(*SI);
      }
    }

    // At this point, S is DFlocal.  Now we union in DFup's of our children...
    // Loop through and visit the nodes that Node immediately dominates (Node's
    // children in the IDomTree)
    bool visitChild = false;
    for (DomTreeNode::const_iterator NI = currentNode->begin(),
           NE = currentNode->end(); NI != NE; ++NI) {
      DomTreeNode *IDominee = *NI;
      BasicBlock *childBB = IDominee->getBlock();
      if (visited.count(childBB) == 0) {
        workList.push_back(DFCalculateWorkObject(childBB, currentBB,
                                                 IDominee, currentNode));
        visitChild = true;
      }
    }

    // If all children are visited or there is any child then pop this block
    // from the workList.
    if (!visitChild) {

      if (!parentBB) {
        Result = &S;
        break;
      }

      DomSetType::const_iterator CDFI = S.begin(), CDFE = S.end();
      DomSetType &parentSet = Frontiers[parentBB];
      for (; CDFI != CDFE; ++CDFI) {
        if (!DT.properlyDominates(parentNode, DT[*CDFI]))
          parentSet.insert(*CDFI);
      }
      workList.pop_back();
    }

  } while (!workList.empty());

  return *Result;
}

void DominanceFrontierBase::print(raw_ostream &OS, const Module* ) const {
  for (const_iterator I = begin(), E = end(); I != E; ++I) {
    OS << "  DomFrontier for BB ";
    if (I->first)
      WriteAsOperand(OS, I->first, false);
    else
      OS << " <<exit node>>";
    OS << " is:\t";

    const std::set<BasicBlock*> &BBs = I->second;

    for (std::set<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
         I != E; ++I) {
      OS << ' ';
      if (*I)
        WriteAsOperand(OS, *I, false);
      else
        OS << "<<exit node>>";
    }
    OS << "\n";
  }
}

<commit_msg>Fix a typo and some indentation.<commit_after>//===- Dominators.cpp - Dominator Calculation -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements simple dominator construction algorithms for finding
// forward dominators.  Postdominators are available in libanalysis, but are not
// included in libvmcore, because it's not needed.  Forward dominators are
// needed to support the Verifier pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Dominators.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/DominatorInternals.h"
#include "llvm/Instructions.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"
#include <algorithm>
using namespace llvm;

// Always verify dominfo if expensive checking is enabled.
#ifdef XDEBUG
bool VerifyDomInfo = true;
#else
bool VerifyDomInfo = false;
#endif
static cl::opt<bool,true>
VerifyDomInfoX("verify-dom-info", cl::location(VerifyDomInfo),
               cl::desc("Verify dominator info (time consuming)"));

//===----------------------------------------------------------------------===//
//  DominatorTree Implementation
//===----------------------------------------------------------------------===//
//
// Provide public access to DominatorTree information.  Implementation details
// can be found in DominatorCalculation.h.
//
//===----------------------------------------------------------------------===//

TEMPLATE_INSTANTIATION(class llvm::DomTreeNodeBase<BasicBlock>);
TEMPLATE_INSTANTIATION(class llvm::DominatorTreeBase<BasicBlock>);

char DominatorTree::ID = 0;
static RegisterPass<DominatorTree>
E("domtree", "Dominator Tree Construction", true, true);

bool DominatorTree::runOnFunction(Function &F) {
  DT->recalculate(F);
  return false;
}

void DominatorTree::verifyAnalysis() const {
  if (!VerifyDomInfo) return;

  Function &F = *getRoot()->getParent();

  DominatorTree OtherDT;
  OtherDT.getBase().recalculate(F);
  assert(!compare(OtherDT) && "Invalid DominatorTree info!");
}

void DominatorTree::print(raw_ostream &OS, const Module *) const {
  DT->print(OS);
}

// dominates - Return true if A dominates a use in B. This performs the
// special checks necessary if A and B are in the same basic block.
bool DominatorTree::dominates(const Instruction *A, const Instruction *B) const{
  const BasicBlock *BBA = A->getParent(), *BBB = B->getParent();

  // If A is an invoke instruction, its value is only available in this normal
  // successor block.
  if (const InvokeInst *II = dyn_cast<InvokeInst>(A))
    BBA = II->getNormalDest();

  if (BBA != BBB) return dominates(BBA, BBB);

  // It is not possible to determine dominance between two PHI nodes
  // based on their ordering.
  if (isa<PHINode>(A) && isa<PHINode>(B))
    return false;

  // Loop through the basic block until we find A or B.
  BasicBlock::const_iterator I = BBA->begin();
  for (; &*I != A && &*I != B; ++I)
    /*empty*/;

  return &*I == A;
}

//===----------------------------------------------------------------------===//
//  DominanceFrontier Implementation
//===----------------------------------------------------------------------===//

char DominanceFrontier::ID = 0;
static RegisterPass<DominanceFrontier>
G("domfrontier", "Dominance Frontier Construction", true, true);

void DominanceFrontier::verifyAnalysis() const {
  if (!VerifyDomInfo) return;

  DominatorTree &DT = getAnalysis<DominatorTree>();

  DominanceFrontier OtherDF;
  const std::vector<BasicBlock*> &DTRoots = DT.getRoots();
  OtherDF.calculate(DT, DT.getNode(DTRoots[0]));
  assert(!compare(OtherDF) && "Invalid DominanceFrontier info!");
}

// NewBB is split and now it has one successor. Update dominance frontier to
// reflect this change.
void DominanceFrontier::splitBlock(BasicBlock *NewBB) {
  assert(NewBB->getTerminator()->getNumSuccessors() == 1
         && "NewBB should have a single successor!");
  BasicBlock *NewBBSucc = NewBB->getTerminator()->getSuccessor(0);

  SmallVector<BasicBlock*, 8> PredBlocks;
  for (pred_iterator PI = pred_begin(NewBB), PE = pred_end(NewBB);
       PI != PE; ++PI)
    PredBlocks.push_back(*PI);

  if (PredBlocks.empty())
    // If NewBB does not have any predecessors then it is a entry block.
    // In this case, NewBB and its successor NewBBSucc dominates all
    // other blocks.
    return;

  // NewBBSucc inherits original NewBB frontier.
  DominanceFrontier::iterator NewBBI = find(NewBB);
  if (NewBBI != end()) {
    DominanceFrontier::DomSetType NewBBSet = NewBBI->second;
    DominanceFrontier::DomSetType NewBBSuccSet;
    NewBBSuccSet.insert(NewBBSet.begin(), NewBBSet.end());
    addBasicBlock(NewBBSucc, NewBBSuccSet);
  }

  // If NewBB dominates NewBBSucc, then DF(NewBB) is now going to be the
  // DF(PredBlocks[0]) without the stuff that the new block does not dominate
  // a predecessor of.
  DominatorTree &DT = getAnalysis<DominatorTree>();
  if (DT.dominates(NewBB, NewBBSucc)) {
    DominanceFrontier::iterator DFI = find(PredBlocks[0]);
    if (DFI != end()) {
      DominanceFrontier::DomSetType Set = DFI->second;
      // Filter out stuff in Set that we do not dominate a predecessor of.
      for (DominanceFrontier::DomSetType::iterator SetI = Set.begin(),
             E = Set.end(); SetI != E;) {
        bool DominatesPred = false;
        for (pred_iterator PI = pred_begin(*SetI), E = pred_end(*SetI);
             PI != E; ++PI)
          if (DT.dominates(NewBB, *PI))
            DominatesPred = true;
        if (!DominatesPred)
          Set.erase(SetI++);
        else
          ++SetI;
      }

      if (NewBBI != end()) {
        for (DominanceFrontier::DomSetType::iterator SetI = Set.begin(),
               E = Set.end(); SetI != E; ++SetI) {
          BasicBlock *SB = *SetI;
          addToFrontier(NewBBI, SB);
        }
      } else
        addBasicBlock(NewBB, Set);
    }

  } else {
    // DF(NewBB) is {NewBBSucc} because NewBB does not strictly dominate
    // NewBBSucc, but it does dominate itself (and there is an edge (NewBB ->
    // NewBBSucc)).  NewBBSucc is the single successor of NewBB.
    DominanceFrontier::DomSetType NewDFSet;
    NewDFSet.insert(NewBBSucc);
    addBasicBlock(NewBB, NewDFSet);
  }

  // Now we must loop over all of the dominance frontiers in the function,
  // replacing occurrences of NewBBSucc with NewBB in some cases.  All
  // blocks that dominate a block in PredBlocks and contained NewBBSucc in
  // their dominance frontier must be updated to contain NewBB instead.
  //
  for (Function::iterator FI = NewBB->getParent()->begin(),
         FE = NewBB->getParent()->end(); FI != FE; ++FI) {
    DominanceFrontier::iterator DFI = find(FI);
    if (DFI == end()) continue;  // unreachable block.

    // Only consider nodes that have NewBBSucc in their dominator frontier.
    if (!DFI->second.count(NewBBSucc)) continue;

    // Verify whether this block dominates a block in predblocks.  If not, do
    // not update it.
    bool BlockDominatesAny = false;
    for (SmallVectorImpl<BasicBlock*>::const_iterator BI = PredBlocks.begin(),
           BE = PredBlocks.end(); BI != BE; ++BI) {
      if (DT.dominates(FI, *BI)) {
        BlockDominatesAny = true;
        break;
      }
    }

    // If NewBBSucc should not stay in our dominator frontier, remove it.
    // We remove it unless there is a predecessor of NewBBSucc that we
    // dominate, but we don't strictly dominate NewBBSucc.
    bool ShouldRemove = true;
    if ((BasicBlock*)FI == NewBBSucc || !DT.dominates(FI, NewBBSucc)) {
      // Okay, we know that PredDom does not strictly dominate NewBBSucc.
      // Check to see if it dominates any predecessors of NewBBSucc.
      for (pred_iterator PI = pred_begin(NewBBSucc),
           E = pred_end(NewBBSucc); PI != E; ++PI)
        if (DT.dominates(FI, *PI)) {
          ShouldRemove = false;
          break;
        }
    }

    if (ShouldRemove)
      removeFromFrontier(DFI, NewBBSucc);
    if (BlockDominatesAny && (&*FI == NewBB || !DT.dominates(FI, NewBB)))
      addToFrontier(DFI, NewBB);
  }
}

namespace {
  class DFCalculateWorkObject {
  public:
    DFCalculateWorkObject(BasicBlock *B, BasicBlock *P,
                          const DomTreeNode *N,
                          const DomTreeNode *PN)
    : currentBB(B), parentBB(P), Node(N), parentNode(PN) {}
    BasicBlock *currentBB;
    BasicBlock *parentBB;
    const DomTreeNode *Node;
    const DomTreeNode *parentNode;
  };
}

const DominanceFrontier::DomSetType &
DominanceFrontier::calculate(const DominatorTree &DT,
                             const DomTreeNode *Node) {
  BasicBlock *BB = Node->getBlock();
  DomSetType *Result = NULL;

  std::vector<DFCalculateWorkObject> workList;
  SmallPtrSet<BasicBlock *, 32> visited;

  workList.push_back(DFCalculateWorkObject(BB, NULL, Node, NULL));
  do {
    DFCalculateWorkObject *currentW = &workList.back();
    assert (currentW && "Missing work object.");

    BasicBlock *currentBB = currentW->currentBB;
    BasicBlock *parentBB = currentW->parentBB;
    const DomTreeNode *currentNode = currentW->Node;
    const DomTreeNode *parentNode = currentW->parentNode;
    assert (currentBB && "Invalid work object. Missing current Basic Block");
    assert (currentNode && "Invalid work object. Missing current Node");
    DomSetType &S = Frontiers[currentBB];

    // Visit each block only once.
    if (visited.count(currentBB) == 0) {
      visited.insert(currentBB);

      // Loop over CFG successors to calculate DFlocal[currentNode]
      for (succ_iterator SI = succ_begin(currentBB), SE = succ_end(currentBB);
           SI != SE; ++SI) {
        // Does Node immediately dominate this successor?
        if (DT[*SI]->getIDom() != currentNode)
          S.insert(*SI);
      }
    }

    // At this point, S is DFlocal.  Now we union in DFup's of our children...
    // Loop through and visit the nodes that Node immediately dominates (Node's
    // children in the IDomTree)
    bool visitChild = false;
    for (DomTreeNode::const_iterator NI = currentNode->begin(),
           NE = currentNode->end(); NI != NE; ++NI) {
      DomTreeNode *IDominee = *NI;
      BasicBlock *childBB = IDominee->getBlock();
      if (visited.count(childBB) == 0) {
        workList.push_back(DFCalculateWorkObject(childBB, currentBB,
                                                 IDominee, currentNode));
        visitChild = true;
      }
    }

    // If all children are visited or there is any child then pop this block
    // from the workList.
    if (!visitChild) {

      if (!parentBB) {
        Result = &S;
        break;
      }

      DomSetType::const_iterator CDFI = S.begin(), CDFE = S.end();
      DomSetType &parentSet = Frontiers[parentBB];
      for (; CDFI != CDFE; ++CDFI) {
        if (!DT.properlyDominates(parentNode, DT[*CDFI]))
          parentSet.insert(*CDFI);
      }
      workList.pop_back();
    }

  } while (!workList.empty());

  return *Result;
}

void DominanceFrontierBase::print(raw_ostream &OS, const Module* ) const {
  for (const_iterator I = begin(), E = end(); I != E; ++I) {
    OS << "  DomFrontier for BB ";
    if (I->first)
      WriteAsOperand(OS, I->first, false);
    else
      OS << " <<exit node>>";
    OS << " is:\t";

    const std::set<BasicBlock*> &BBs = I->second;

    for (std::set<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
         I != E; ++I) {
      OS << ' ';
      if (*I)
        WriteAsOperand(OS, *I, false);
      else
        OS << "<<exit node>>";
    }
    OS << "\n";
  }
}

<|endoftext|>


<commit_before>/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011,2012 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

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

	This program 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <iostream>
#include <fstream>

#include <Configuration.h>
// Load configuration from a file.
ConfigurationTable gConfig("/etc/OpenBTS/OpenBTS.db");

#include <TRXManager.h>
#include <GSML1FEC.h>
#include <GSMConfig.h>
#include <GSMSAPMux.h>
#include <GSML3RRMessages.h>
#include <GSMLogicalChannel.h>

#include <ControlCommon.h>
#include <TransactionTable.h>

#include <SIPInterface.h>
#include <Globals.h>

#include <Logger.h>
#include <CLI.h>
#include <PowerManager.h>
#include <Configuration.h>
#include <PhysicalStatus.h>
#include <SubscriberRegistry.h>

#include <sys/wait.h>

#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

using namespace std;
using namespace GSM;

const char* gDateTime = __DATE__ " " __TIME__;

// All of the other globals that rely on the global configuration file need to
// be declared here.

// The TMSI Table.
Control::TMSITable gTMSITable;

// The transaction table.
Control::TransactionTable gTransactionTable;

// Physical status reporting
GSM::PhysicalStatus gPhysStatus;

// The global SIPInterface object.
SIP::SIPInterface gSIPInterface;

// Configure the BTS object based on the config file.
// So don't create this until AFTER loading the config file.
GSMConfig gBTS;

// Our interface to the software-defined radio.
TransceiverManager gTRX(gConfig.getNum("GSM.Radio.ARFCNs"), gConfig.getStr("TRX.IP").c_str(), gConfig.getNum("TRX.Port"));

// Subscriber registry
SubscriberRegistry gSubscriberRegistry;

/** Define a function to call any time the configuration database changes. */
void purgeConfig(void*,int,char const*, char const*, sqlite3_int64)
{
	LOG(INFO) << "purging configuration cache";
	gConfig.purge();
	gBTS.regenerateBeacon();
}

const char* transceiverPath = "./transceiver";

pid_t gTransceiverPid = 0;

void startTransceiver()
{
	// kill any stray transceiver process
	system("killall transceiver");

	// Start the transceiver binary, if the path is defined.
	// If the path is not defined, the transceiver must be started by some other process.
	char TRXnumARFCN[4];
	sprintf(TRXnumARFCN,"%1d",gConfig.getNum("GSM.Radio.ARFCNs"));
	LOG(NOTICE) << "starting transceiver " << transceiverPath << " " << TRXnumARFCN;
	gTransceiverPid = vfork();
	LOG_ASSERT(gTransceiverPid>=0);
	if (gTransceiverPid==0) {
		// Pid==0 means this is the process that starts the transceiver.
		execlp(transceiverPath,transceiverPath,TRXnumARFCN,NULL);
		LOG(EMERG) << "cannot find " << transceiverPath;
		_exit(1);
	} else {
		int status;
		waitpid(gTransceiverPid, &status,0);
		LOG(EMERG) << "Transceiver quit with status " << status << ". Exiting.";
		exit(2);
	}
}

int main(int argc, char *argv[])
{
	// TODO: Properly parse and handle any arguments
	if (argc > 1) {
		for (int argi = 0; argi < argc; argi++) {
			if (!strcmp(argv[argi], "--version") ||
			    !strcmp(argv[argi], "-v")) {
				cout << gVersionString << endl;
			}
		}

		return 0;
	}

	int sock = socket(AF_UNIX,SOCK_DGRAM,0);
	if (sock<0) {
		perror("opening cmd datagram socket");
		exit(1);
	}

	try {

	srandom(time(NULL));

	gConfig.setUpdateHook(purgeConfig);
	gLogInit("openbts",gConfig.getStr("Log.Level").c_str(),LOG_LOCAL7);
	LOG(ALERT) << "OpenBTS starting, ver " << VERSION << " build date " << __DATE__;

	COUT("\n\n" << gOpenBTSWelcome << "\n");
	gTMSITable.open(gConfig.getStr("Control.Reporting.TMSITable").c_str());
	gTransactionTable.init(gConfig.getStr("Control.Reporting.TransactionTable").c_str());
	gPhysStatus.open(gConfig.getStr("Control.Reporting.PhysStatusTable").c_str());
	gBTS.init();
	gSubscriberRegistry.init();
	gParser.addCommands();

	COUT("\nStarting the system...");

	// is the radio running?
	// Start the transceiver interface.
	LOG(INFO) << "checking transceiver";
	//gTRX.ARFCN(0)->powerOn();
	//sleep(gConfig.getNum("TRX.Timeout.Start",2));
	bool haveTRX = gTRX.ARFCN(0)->powerOn();

	Thread transceiverThread;
	if (!gTRX.haveClock()) {
		transceiverThread.start((void*(*)(void*)) startTransceiver, NULL);
		// sleep to let the FPGA code load
		// TODO: we should be "pinging" the radio instead of sleeping
		sleep(5);
	} else {
		LOG(NOTICE) << "transceiver already running";
	}

	// Start the SIP interface.
	gSIPInterface.start();

	//
	// Configure the radio.
	//

	gTRX.start();

	// Set up the interface to the radio.
	// Get a handle to the C0 transceiver interface.
	ARFCNManager* C0radio = gTRX.ARFCN(0);

	// Tuning.
	// Make sure its off for tuning.
	//C0radio->powerOff();
	// Get the ARFCN list.
	unsigned C0 = gConfig.getNum("GSM.Radio.C0");
	unsigned numARFCNs = gConfig.getNum("GSM.Radio.ARFCNs");
	for (unsigned i=0; i<numARFCNs; i++) {
		// Tune the radios.
		unsigned ARFCN = C0 + i*2;
		LOG(INFO) << "tuning TRX " << i << " to ARFCN " << ARFCN;
		ARFCNManager* radio = gTRX.ARFCN(i);
		radio->tune(ARFCN);
	}

	// Set TSC same as BCC everywhere.
	C0radio->setTSC(gBTS.BCC());

	// Set maximum expected delay spread.
	C0radio->setMaxDelay(gConfig.getNum("GSM.Radio.MaxExpectedDelaySpread"));

	// Set Receiver Gain
	C0radio->setRxGain(gConfig.getNum("GSM.Radio.RxGain"));

	// Turn on and power up.
	C0radio->powerOn();
	C0radio->setPower(gConfig.getNum("GSM.Radio.PowerManager.MinAttenDB"));

	//
	// Create a C-V channel set on C0T0.
	//

	// C-V on C0T0
	C0radio->setSlot(0,5);
	// SCH
	SCHL1FEC SCH;
	SCH.downstream(C0radio);
	SCH.open();
	// FCCH
	FCCHL1FEC FCCH;
	FCCH.downstream(C0radio);
	FCCH.open();
	// BCCH
	BCCHL1FEC BCCH;
	BCCH.downstream(C0radio);
	BCCH.open();
	// RACH
	RACHL1FEC RACH(gRACHC5Mapping);
	RACH.downstream(C0radio);
	RACH.open();
	// CCCHs
	CCCHLogicalChannel CCCH0(gCCCH_0Mapping);
	CCCH0.downstream(C0radio);
	CCCH0.open();
	CCCHLogicalChannel CCCH1(gCCCH_1Mapping);
	CCCH1.downstream(C0radio);
	CCCH1.open();
	CCCHLogicalChannel CCCH2(gCCCH_2Mapping);
	CCCH2.downstream(C0radio);
	CCCH2.open();
	// use CCCHs as AGCHs
	gBTS.addAGCH(&CCCH0);
	gBTS.addAGCH(&CCCH1);
	gBTS.addAGCH(&CCCH2);

	// C-V C0T0 SDCCHs
	SDCCHLogicalChannel C0T0SDCCH[4] = {
		SDCCHLogicalChannel(0,0,gSDCCH_4_0),
		SDCCHLogicalChannel(0,0,gSDCCH_4_1),
		SDCCHLogicalChannel(0,0,gSDCCH_4_2),
		SDCCHLogicalChannel(0,0,gSDCCH_4_3),
	};
	Thread C0T0SDCCHControlThread[4];
	for (int i=0; i<4; i++) {
		C0T0SDCCH[i].downstream(C0radio);
		C0T0SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&C0T0SDCCH[i]);
		C0T0SDCCH[i].open();
		gBTS.addSDCCH(&C0T0SDCCH[i]);
	}

	//
	// Configure the other slots.
	//

	// Count configured slots.
	unsigned sCount = 1;

	if (gConfig.defines("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount/8,sCount%8);
			sCount++;
		}
	}

	// Create C-VII slots.
	for (int i=0; i<gConfig.getNum("GSM.Channels.NumC7s"); i++) {
		gBTS.createCombinationVII(gTRX,sCount/8,sCount%8);
		sCount++;
	}

	if (!gConfig.defines("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount/8,sCount%8);
			sCount++;
		}
	}

	// Set up idle filling on C0 as needed.
	while (sCount<8) {
		gBTS.createCombination0(gTRX,sCount);
		sCount++;
	}

	/*
		Note: The number of different paging subchannels on
		the CCCH is:

		MAX(1,(3 - BS-AG-BLKS-RES)) * BS-PA-MFRMS
			if CCCH-CONF = "001"
		(9 - BS-AG-BLKS-RES) * BS-PA-MFRMS
			for other values of CCCH-CONF
	*/

	// Set up the pager.
	// Set up paging channels.
	// HACK -- For now, use a single paging channel, since paging groups are broken.
	gBTS.addPCH(&CCCH2);

	// Be sure we are not over-reserving.
	LOG_ASSERT(gConfig.getNum("GSM.CCCH.PCH.Reserve")<(int)gBTS.numAGCHs());

	// OK, now it is safe to start the BTS.
	gBTS.start();

	cout << "\nsystem ready\n";
	cout << "\nuse the OpenBTSCLI utility to access CLI\n";
	LOG(INFO) << "system ready";

	struct sockaddr_un cmdSockName;
	cmdSockName.sun_family = AF_UNIX;
	const char* sockpath = gConfig.getStr("CLI.SocketPath","/var/run/OpenBTS/command").c_str();
	char rmcmd[strlen(sockpath)+5];
	sprintf(rmcmd,"rm %s",sockpath);
	system(rmcmd);
	strcpy(cmdSockName.sun_path,sockpath);
	if (bind(sock, (struct sockaddr *) &cmdSockName, sizeof(struct sockaddr_un))) {
		perror("binding name to cmd datagram socket");
		exit(1);
	}

	while (1) {
		char cmdbuf[1000];
		struct sockaddr_un source;
		socklen_t sourceSize = sizeof(source);
		int nread = recvfrom(sock,cmdbuf,sizeof(cmdbuf)-1,0,(struct sockaddr*)&source,&sourceSize);
		cmdbuf[nread]='\0';
		LOG(INFO) << "received command \"" << cmdbuf << "\" from " << source.sun_path;
		std::ostringstream sout;
		int res = gParser.process(cmdbuf,sout);
		const std::string rspString= sout.str();
		const char* rsp = rspString.c_str();
		LOG(INFO) << "sending " << strlen(rsp) << "-char result to " << source.sun_path;
		if (sendto(sock,rsp,strlen(rsp)+1,0,(struct sockaddr*)&source,sourceSize)<0) {
			LOG(ERR) << "can't send CLI response to " << source.sun_path;
		}
		// res<0 means to exit the application
		if (res<0) break;
	}

	} // try

	catch (ConfigurationTableKeyNotFound e) {
		LOG(EMERG) << "required configuration parameter " << e.key() << " not defined, aborting";
	}

	//if (gTransceiverPid) kill(gTransceiverPid, SIGKILL);
	close(sock);

}

// vim: ts=4 sw=4
<commit_msg>r4426 in private: Check for transceiver with a "ping", not be waiting for the clock. The fixes in the socket class seem to have solved this problem.<commit_after>/*
* Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011,2012 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

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

	This program 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <iostream>
#include <fstream>

#include <Configuration.h>
// Load configuration from a file.
ConfigurationTable gConfig("/etc/OpenBTS/OpenBTS.db");

#include <TRXManager.h>
#include <GSML1FEC.h>
#include <GSMConfig.h>
#include <GSMSAPMux.h>
#include <GSML3RRMessages.h>
#include <GSMLogicalChannel.h>

#include <ControlCommon.h>
#include <TransactionTable.h>

#include <SIPInterface.h>
#include <Globals.h>

#include <Logger.h>
#include <CLI.h>
#include <PowerManager.h>
#include <Configuration.h>
#include <PhysicalStatus.h>
#include <SubscriberRegistry.h>

#include <sys/wait.h>

#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

using namespace std;
using namespace GSM;

const char* gDateTime = __DATE__ " " __TIME__;

// All of the other globals that rely on the global configuration file need to
// be declared here.

// The TMSI Table.
Control::TMSITable gTMSITable;

// The transaction table.
Control::TransactionTable gTransactionTable;

// Physical status reporting
GSM::PhysicalStatus gPhysStatus;

// The global SIPInterface object.
SIP::SIPInterface gSIPInterface;

// Configure the BTS object based on the config file.
// So don't create this until AFTER loading the config file.
GSMConfig gBTS;

// Our interface to the software-defined radio.
TransceiverManager gTRX(gConfig.getNum("GSM.Radio.ARFCNs"), gConfig.getStr("TRX.IP").c_str(), gConfig.getNum("TRX.Port"));

// Subscriber registry
SubscriberRegistry gSubscriberRegistry;

/** Define a function to call any time the configuration database changes. */
void purgeConfig(void*,int,char const*, char const*, sqlite3_int64)
{
	LOG(INFO) << "purging configuration cache";
	gConfig.purge();
	gBTS.regenerateBeacon();
}

const char* transceiverPath = "./transceiver";

pid_t gTransceiverPid = 0;

void startTransceiver()
{
	// kill any stray transceiver process
	system("killall transceiver");

	// Start the transceiver binary, if the path is defined.
	// If the path is not defined, the transceiver must be started by some other process.
	char TRXnumARFCN[4];
	sprintf(TRXnumARFCN,"%1d",gConfig.getNum("GSM.Radio.ARFCNs"));
	LOG(NOTICE) << "starting transceiver " << transceiverPath << " " << TRXnumARFCN;
	gTransceiverPid = vfork();
	LOG_ASSERT(gTransceiverPid>=0);
	if (gTransceiverPid==0) {
		// Pid==0 means this is the process that starts the transceiver.
		execlp(transceiverPath,transceiverPath,TRXnumARFCN,NULL);
		LOG(EMERG) << "cannot find " << transceiverPath;
		_exit(1);
	} else {
		int status;
		waitpid(gTransceiverPid, &status,0);
		LOG(EMERG) << "Transceiver quit with status " << status << ". Exiting.";
		exit(2);
	}
}

int main(int argc, char *argv[])
{
	// TODO: Properly parse and handle any arguments
	if (argc > 1) {
		for (int argi = 0; argi < argc; argi++) {
			if (!strcmp(argv[argi], "--version") ||
			    !strcmp(argv[argi], "-v")) {
				cout << gVersionString << endl;
			}
		}

		return 0;
	}

	int sock = socket(AF_UNIX,SOCK_DGRAM,0);
	if (sock<0) {
		perror("opening cmd datagram socket");
		exit(1);
	}

	try {

	srandom(time(NULL));

	gConfig.setUpdateHook(purgeConfig);
	gLogInit("openbts",gConfig.getStr("Log.Level").c_str(),LOG_LOCAL7);
	LOG(ALERT) << "OpenBTS starting, ver " << VERSION << " build date " << __DATE__;

	COUT("\n\n" << gOpenBTSWelcome << "\n");
	gTMSITable.open(gConfig.getStr("Control.Reporting.TMSITable").c_str());
	gTransactionTable.init(gConfig.getStr("Control.Reporting.TransactionTable").c_str());
	gPhysStatus.open(gConfig.getStr("Control.Reporting.PhysStatusTable").c_str());
	gBTS.init();
	gSubscriberRegistry.init();
	gParser.addCommands();

	COUT("\nStarting the system...");

	// is the radio running?
	// Start the transceiver interface.
	LOG(INFO) << "checking transceiver";
	//gTRX.ARFCN(0)->powerOn();
	//sleep(gConfig.getNum("TRX.Timeout.Start",2));
	bool haveTRX = gTRX.ARFCN(0)->powerOn();

	Thread transceiverThread;
	if (!haveTRX) {
		transceiverThread.start((void*(*)(void*)) startTransceiver, NULL);
		// sleep to let the FPGA code load
		// TODO: we should be "pinging" the radio instead of sleeping
		sleep(5);
	} else {
		LOG(NOTICE) << "transceiver already running";
	}

	// Start the SIP interface.
	gSIPInterface.start();

	//
	// Configure the radio.
	//

	gTRX.start();

	// Set up the interface to the radio.
	// Get a handle to the C0 transceiver interface.
	ARFCNManager* C0radio = gTRX.ARFCN(0);

	// Tuning.
	// Make sure its off for tuning.
	//C0radio->powerOff();
	// Get the ARFCN list.
	unsigned C0 = gConfig.getNum("GSM.Radio.C0");
	unsigned numARFCNs = gConfig.getNum("GSM.Radio.ARFCNs");
	for (unsigned i=0; i<numARFCNs; i++) {
		// Tune the radios.
		unsigned ARFCN = C0 + i*2;
		LOG(INFO) << "tuning TRX " << i << " to ARFCN " << ARFCN;
		ARFCNManager* radio = gTRX.ARFCN(i);
		radio->tune(ARFCN);
	}

	// Set TSC same as BCC everywhere.
	C0radio->setTSC(gBTS.BCC());

	// Set maximum expected delay spread.
	C0radio->setMaxDelay(gConfig.getNum("GSM.Radio.MaxExpectedDelaySpread"));

	// Set Receiver Gain
	C0radio->setRxGain(gConfig.getNum("GSM.Radio.RxGain"));

	// Turn on and power up.
	C0radio->powerOn();
	C0radio->setPower(gConfig.getNum("GSM.Radio.PowerManager.MinAttenDB"));

	//
	// Create a C-V channel set on C0T0.
	//

	// C-V on C0T0
	C0radio->setSlot(0,5);
	// SCH
	SCHL1FEC SCH;
	SCH.downstream(C0radio);
	SCH.open();
	// FCCH
	FCCHL1FEC FCCH;
	FCCH.downstream(C0radio);
	FCCH.open();
	// BCCH
	BCCHL1FEC BCCH;
	BCCH.downstream(C0radio);
	BCCH.open();
	// RACH
	RACHL1FEC RACH(gRACHC5Mapping);
	RACH.downstream(C0radio);
	RACH.open();
	// CCCHs
	CCCHLogicalChannel CCCH0(gCCCH_0Mapping);
	CCCH0.downstream(C0radio);
	CCCH0.open();
	CCCHLogicalChannel CCCH1(gCCCH_1Mapping);
	CCCH1.downstream(C0radio);
	CCCH1.open();
	CCCHLogicalChannel CCCH2(gCCCH_2Mapping);
	CCCH2.downstream(C0radio);
	CCCH2.open();
	// use CCCHs as AGCHs
	gBTS.addAGCH(&CCCH0);
	gBTS.addAGCH(&CCCH1);
	gBTS.addAGCH(&CCCH2);

	// C-V C0T0 SDCCHs
	SDCCHLogicalChannel C0T0SDCCH[4] = {
		SDCCHLogicalChannel(0,0,gSDCCH_4_0),
		SDCCHLogicalChannel(0,0,gSDCCH_4_1),
		SDCCHLogicalChannel(0,0,gSDCCH_4_2),
		SDCCHLogicalChannel(0,0,gSDCCH_4_3),
	};
	Thread C0T0SDCCHControlThread[4];
	for (int i=0; i<4; i++) {
		C0T0SDCCH[i].downstream(C0radio);
		C0T0SDCCHControlThread[i].start((void*(*)(void*))Control::DCCHDispatcher,&C0T0SDCCH[i]);
		C0T0SDCCH[i].open();
		gBTS.addSDCCH(&C0T0SDCCH[i]);
	}

	//
	// Configure the other slots.
	//

	// Count configured slots.
	unsigned sCount = 1;

	if (gConfig.defines("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount/8,sCount%8);
			sCount++;
		}
	}

	// Create C-VII slots.
	for (int i=0; i<gConfig.getNum("GSM.Channels.NumC7s"); i++) {
		gBTS.createCombinationVII(gTRX,sCount/8,sCount%8);
		sCount++;
	}

	if (!gConfig.defines("GSM.Channels.C1sFirst")) {
		// Create C-I slots.
		for (int i=0; i<gConfig.getNum("GSM.Channels.NumC1s"); i++) {
			gBTS.createCombinationI(gTRX,sCount/8,sCount%8);
			sCount++;
		}
	}

	// Set up idle filling on C0 as needed.
	while (sCount<8) {
		gBTS.createCombination0(gTRX,sCount);
		sCount++;
	}

	/*
		Note: The number of different paging subchannels on
		the CCCH is:

		MAX(1,(3 - BS-AG-BLKS-RES)) * BS-PA-MFRMS
			if CCCH-CONF = "001"
		(9 - BS-AG-BLKS-RES) * BS-PA-MFRMS
			for other values of CCCH-CONF
	*/

	// Set up the pager.
	// Set up paging channels.
	// HACK -- For now, use a single paging channel, since paging groups are broken.
	gBTS.addPCH(&CCCH2);

	// Be sure we are not over-reserving.
	LOG_ASSERT(gConfig.getNum("GSM.CCCH.PCH.Reserve")<(int)gBTS.numAGCHs());

	// OK, now it is safe to start the BTS.
	gBTS.start();

	cout << "\nsystem ready\n";
	cout << "\nuse the OpenBTSCLI utility to access CLI\n";
	LOG(INFO) << "system ready";

	struct sockaddr_un cmdSockName;
	cmdSockName.sun_family = AF_UNIX;
	const char* sockpath = gConfig.getStr("CLI.SocketPath","/var/run/OpenBTS/command").c_str();
	char rmcmd[strlen(sockpath)+5];
	sprintf(rmcmd,"rm %s",sockpath);
	system(rmcmd);
	strcpy(cmdSockName.sun_path,sockpath);
	if (bind(sock, (struct sockaddr *) &cmdSockName, sizeof(struct sockaddr_un))) {
		perror("binding name to cmd datagram socket");
		exit(1);
	}

	while (1) {
		char cmdbuf[1000];
		struct sockaddr_un source;
		socklen_t sourceSize = sizeof(source);
		int nread = recvfrom(sock,cmdbuf,sizeof(cmdbuf)-1,0,(struct sockaddr*)&source,&sourceSize);
		cmdbuf[nread]='\0';
		LOG(INFO) << "received command \"" << cmdbuf << "\" from " << source.sun_path;
		std::ostringstream sout;
		int res = gParser.process(cmdbuf,sout);
		const std::string rspString= sout.str();
		const char* rsp = rspString.c_str();
		LOG(INFO) << "sending " << strlen(rsp) << "-char result to " << source.sun_path;
		if (sendto(sock,rsp,strlen(rsp)+1,0,(struct sockaddr*)&source,sourceSize)<0) {
			LOG(ERR) << "can't send CLI response to " << source.sun_path;
		}
		// res<0 means to exit the application
		if (res<0) break;
	}

	} // try

	catch (ConfigurationTableKeyNotFound e) {
		LOG(EMERG) << "required configuration parameter " << e.key() << " not defined, aborting";
	}

	//if (gTransceiverPid) kill(gTransceiverPid, SIGKILL);
	close(sock);

}

// vim: ts=4 sw=4
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkFunction.h"
#include "Test.h"

static void test_add_five(skiatest::Reporter* r, SkFunction<int(int)>&& f) {
    REPORTER_ASSERT(r, f(3) == 8);
    REPORTER_ASSERT(r, f(4) == 9);
}

static int add_five(int x) { return x + 5; }

struct AddFive {
    int operator()(int x) { return x + 5; };
};

class MoveOnlyAdd5 : SkNoncopyable {
public:
    MoveOnlyAdd5() {}
    MoveOnlyAdd5(MoveOnlyAdd5&&) {}
    MoveOnlyAdd5& operator=(MoveOnlyAdd5&&) { return *this; }

    int operator()(int x) { return x + 5; }
};

DEF_TEST(Function, r) {
    // We should be able to turn a static function, an explicit functor, or a lambda
    // all into an SkFunction equally well.
    test_add_five(r, &add_five);
    test_add_five(r, AddFive());
    test_add_five(r, [](int x) { return x + 5; });

    // AddFive and the lambda above are both small enough to test small-object optimization.
    // Now test a lambda that's much too large for the small-object optimization.
    int a = 1, b = 1, c = 1, d = 1, e = 1;
    test_add_five(r, [&](int x) { return x + a + b + c + d + e; });

    // Makes sure we forward the functor when constructing SkFunction.
    test_add_five(r, MoveOnlyAdd5());

    // Makes sure we forward arguments when calling SkFunction.
    REPORTER_ASSERT(r, [](int x, MoveOnlyAdd5&& f, int y) {
        return x * f(y);
    }(2, MoveOnlyAdd5(), 4) == 18);
}
<commit_msg>That last CL subverted the purpose of the test.  Put it back how it was.<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkFunction.h"
#include "Test.h"

static void test_add_five(skiatest::Reporter* r, SkFunction<int(int)>&& f) {
    REPORTER_ASSERT(r, f(3) == 8);
    REPORTER_ASSERT(r, f(4) == 9);
}

static int add_five(int x) { return x + 5; }

struct AddFive {
    int operator()(int x) { return x + 5; };
};

class MoveOnlyAdd5 : SkNoncopyable {
public:
    MoveOnlyAdd5() {}
    MoveOnlyAdd5(MoveOnlyAdd5&&) {}
    MoveOnlyAdd5& operator=(MoveOnlyAdd5&&) { return *this; }

    int operator()(int x) { return x + 5; }
};

DEF_TEST(Function, r) {
    // We should be able to turn a static function, an explicit functor, or a lambda
    // all into an SkFunction equally well.
    test_add_five(r, &add_five);
    test_add_five(r, AddFive());
    test_add_five(r, [](int x) { return x + 5; });

    // AddFive and the lambda above are both small enough to test small-object optimization.
    // Now test a lambda that's much too large for the small-object optimization.
    int a = 1, b = 1, c = 1, d = 1, e = 1;
    test_add_five(r, [&](int x) { return x + a + b + c + d + e; });

    // Makes sure we forward the functor when constructing SkFunction.
    test_add_five(r, MoveOnlyAdd5());

    // Makes sure we forward arguments when calling SkFunction.
    SkFunction<int(int, MoveOnlyAdd5&&, int)> f([](int x, MoveOnlyAdd5&& addFive, int y) {
            return x * addFive(y);
    });
    REPORTER_ASSERT(r, f(2, MoveOnlyAdd5(), 4) == 18);
}
<|endoftext|>