<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "GLXContext.h"
#include "GLContextAttribs.h"
#include "X11Display.h"

#include "../base/Exception.h"
#include "../base/Logger.h"

#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>

#include <X11/extensions/xf86vmode.h>

#include <iostream>
#include <stdlib.h>

namespace avg {

using namespace std;
using namespace boost;

static bool s_bX11Error;
static bool s_bDumpX11ErrorMsg;
static int (*s_DefaultErrorHandler) (::Display *, XErrorEvent *);

GLXContext::GLXContext(const IntPoint& windowSize)
    : GLContext(windowSize),
      m_pDisplay(0),
      m_bVBlankActive(false)
{
    s_bX11Error = false;
}

GLXContext::~GLXContext()
{
    deleteObjects();
    if (m_Context && ownsContext()) {
        glXMakeCurrent(m_pDisplay, 0, 0);
        glXDestroyContext(m_pDisplay, m_Context);
        m_Context = 0;
        XFreeColormap(m_pDisplay, m_Colormap);
    }
}

void GLXContext::activate()
{
    glXMakeCurrent(m_pDisplay, m_Drawable, m_Context);
    setCurrent();
}

bool GLXContext::initVBlank(int rate)
{
    if (rate > 0) {
        if (getenv("__GL_SYNC_TO_VBLANK") != 0) {
            AVG_LOG_WARNING("__GL_SYNC_TO_VBLANK set. This interferes with libavg vblank handling.");
            m_bVBlankActive = false;
            return false;
        }
        if (!queryGLXExtension("GLX_EXT_swap_control")) {
            AVG_LOG_WARNING("Linux VBlank setup failed: OpenGL Extension not supported.");
            m_bVBlankActive = false;
            return false;
        }

        glproc::SwapIntervalEXT(m_pDisplay, m_Drawable, rate);
        m_bVBlankActive = true;
        return true;

    } else {
        if (m_bVBlankActive) {
            glproc::SwapIntervalEXT(m_pDisplay, m_Drawable, 0);
            m_bVBlankActive = false;
        }
        return false;
    }
}

bool GLXContext::useDepthBuffer() const
{
    // NVidia GLX GLES doesn't allow framebuffer stencil without depth.
    return true;
}

void GLXContext::swapBuffers()
{
    glXSwapBuffers(m_pDisplay, m_Drawable);
}

bool GLXContext::haveARBCreateContext()
{
    static bool s_bExtensionChecked = false;
    static bool s_bHaveExtension = false;
    if (!s_bExtensionChecked) {
        s_bExtensionChecked = true;
        s_bHaveExtension = (queryGLXExtension("GLX_ARB_create_context"));
    }
    return s_bHaveExtension;
}

XVisualInfo* GLXContext::createDetachedContext(::Display* pDisplay, GLConfig& glConfig)
{
    m_pDisplay = pDisplay;
    GLXFBConfig fbConfig = getFBConfig(m_pDisplay, glConfig);
    XVisualInfo* pVisualInfo = glXGetVisualFromFBConfig(m_pDisplay, fbConfig);

    if (haveARBCreateContext()) {
        GLContextAttribs attrs;
        GLContextAttribs attrsWODebug;
        if (glConfig.m_bGLES) {
            attrs.append(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT);
            attrs.append(GLX_CONTEXT_MAJOR_VERSION_ARB, 2);
            attrs.append(GLX_CONTEXT_MINOR_VERSION_ARB, 0);
        }
        if (glConfig.m_bUseDebugContext) {
            attrsWODebug = attrs;
            attrs.append(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
        }
        PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB =
            (PFNGLXCREATECONTEXTATTRIBSARBPROC)
            getglXProcAddress("glXCreateContextAttribsARB");

        s_bDumpX11ErrorMsg = false;
        m_Context = CreateContextAttribsARB(m_pDisplay, fbConfig, 0, 1, attrs.get());
        if(!m_Context && glConfig.m_bUseDebugContext) {
            //On intel HW ContextCreation with DebugBit fails
            AVG_LOG_WARNING("Failed to create DEBUG context… falling back to standard context");
            s_bX11Error = false;
            m_Context = CreateContextAttribsARB(m_pDisplay, fbConfig, 0, 1, attrsWODebug.get());
            AVG_ASSERT(m_Context);
        }
        s_bDumpX11ErrorMsg = true;
        throwOnXError(AVG_ERR_DEBUG_CONTEXT_FAILED);
    } else {
        m_Context = glXCreateContext(m_pDisplay, pVisualInfo, 0, GL_TRUE);
    }
    AVG_ASSERT(m_Context);

    m_Colormap = XCreateColormap(pDisplay, RootWindow(m_pDisplay, pVisualInfo->screen),
            pVisualInfo->visual, AllocNone);
    AVG_ASSERT(m_Colormap);

    return pVisualInfo;
}

void GLXContext::setX11ErrorHandler()
{
    s_bDumpX11ErrorMsg = true;
    s_DefaultErrorHandler = XSetErrorHandler(X11ErrorHandler);
}

void GLXContext::resetX11ErrorHandler()
{
    XSetErrorHandler(s_DefaultErrorHandler);
}

void GLXContext::throwOnXError(int code)
{
    if (s_bX11Error) {
        throw Exception(code, "X error creating OpenGL context.");
    }
}

void GLXContext::initDrawable()
{
    m_Drawable = glXGetCurrentDrawable();
}

::GLXContext GLXContext::getGLXContext() const
{
    return m_Context;
}

::Display* GLXContext::getDisplay() const
{
    return m_pDisplay;
}

Colormap GLXContext::getColormap() const
{
    return m_Colormap;
}

GLXFBConfig GLXContext::getFBConfig(::Display* pDisplay, GLConfig& glConfig)
{
    GLContextAttribs attrs;
    attrs.append(GLX_X_RENDERABLE, 1);
    attrs.append(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
    attrs.append(GLX_RENDER_TYPE, GLX_RGBA_BIT);
    attrs.append(GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR);
    attrs.append(GLX_DEPTH_SIZE, 0);
    attrs.append(GLX_STENCIL_SIZE, 8);
    attrs.append(GLX_DOUBLEBUFFER, 1);
    attrs.append(GLX_RED_SIZE, 8);
    attrs.append(GLX_GREEN_SIZE, 8);
    attrs.append(GLX_BLUE_SIZE, 8);
    attrs.append(GLX_ALPHA_SIZE, 0);

    int fbCount;
    GLXFBConfig* pFBConfig = glXChooseFBConfig(m_pDisplay, DefaultScreen(m_pDisplay),
            attrs.get(), &fbCount);
    if (!pFBConfig) {
        throw Exception(AVG_ERR_UNSUPPORTED, "Creating OpenGL context failed.");
    }

    // Find the config with the appropriate number of multisample samples.
    int bestConfig = -1;
    int bestSamples = -1;
    int bestCaveat = std::numeric_limits<int>::max();
    for (int i=0; i<fbCount; ++i) {
        XVisualInfo* pVisualInfo = glXGetVisualFromFBConfig(m_pDisplay, pFBConfig[i]);
        if (pVisualInfo && pVisualInfo->depth == 24) {
            int numBuffers;
            int numSamples;
            int caveat;
            glXGetFBConfigAttrib(m_pDisplay, pFBConfig[i], GLX_SAMPLE_BUFFERS,
                    &numBuffers);
            glXGetFBConfigAttrib(m_pDisplay, pFBConfig[i], GLX_SAMPLES, &numSamples);
            glXGetFBConfigAttrib(m_pDisplay, pFBConfig[i], GLX_CONFIG_CAVEAT, &caveat);
            if (numSamples == 0) {
                // Configs without multisampling have numBuffers == 0 and numSamples == 0,
                // but the corresponding libavg config is multisamplesamples == 1.
                numSamples = 1;
            }
            if ((numSamples > bestSamples && numSamples <= glConfig.m_MultiSampleSamples)
                  || (numSamples == bestSamples && caveat < bestCaveat))
            {
                // A config is better than the last one in two cases:
                //    1) it has more samples per pixel (but not more than requested) or
                //    2) it has the same number of samples per pixel but a better caveat
                //       value.
                bestCaveat = caveat;
                bestConfig = i;
                bestSamples = numSamples;
            }
            XFree(pVisualInfo);
        }
    }
    glConfig.m_MultiSampleSamples = bestSamples;
    GLXFBConfig fbConfig = pFBConfig[bestConfig];
    XFree(pFBConfig);
    return fbConfig;
}

int GLXContext::X11ErrorHandler(::Display * pDisplay, XErrorEvent * pErrEvent)
{
    if (s_bDumpX11ErrorMsg) {
        char errorString[128];
        XGetErrorText(pDisplay, pErrEvent->error_code, errorString, 128);
        cerr << "X11 error creating GL context: " << errorString <<
            "\n\tMajor opcode of failed request: " << (int)(pErrEvent->request_code) <<
            "\n\tMinor opcode of failed request: " << (int)(pErrEvent->minor_code) <<
            "\n";
    }
    s_bX11Error = true;
    return 0;
}

}
<commit_msg>Enable X11ErrorMsg handling before trying to create fallback GLX-Context<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "GLXContext.h"
#include "GLContextAttribs.h"
#include "X11Display.h"

#include "../base/Exception.h"
#include "../base/Logger.h"

#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>

#include <X11/extensions/xf86vmode.h>

#include <iostream>
#include <stdlib.h>

namespace avg {

using namespace std;
using namespace boost;

static bool s_bX11Error;
static bool s_bDumpX11ErrorMsg;
static int (*s_DefaultErrorHandler) (::Display *, XErrorEvent *);

GLXContext::GLXContext(const IntPoint& windowSize)
    : GLContext(windowSize),
      m_pDisplay(0),
      m_bVBlankActive(false)
{
    s_bX11Error = false;
}

GLXContext::~GLXContext()
{
    deleteObjects();
    if (m_Context && ownsContext()) {
        glXMakeCurrent(m_pDisplay, 0, 0);
        glXDestroyContext(m_pDisplay, m_Context);
        m_Context = 0;
        XFreeColormap(m_pDisplay, m_Colormap);
    }
}

void GLXContext::activate()
{
    glXMakeCurrent(m_pDisplay, m_Drawable, m_Context);
    setCurrent();
}

bool GLXContext::initVBlank(int rate)
{
    if (rate > 0) {
        if (getenv("__GL_SYNC_TO_VBLANK") != 0) {
            AVG_LOG_WARNING("__GL_SYNC_TO_VBLANK set. This interferes with libavg vblank handling.");
            m_bVBlankActive = false;
            return false;
        }
        if (!queryGLXExtension("GLX_EXT_swap_control")) {
            AVG_LOG_WARNING("Linux VBlank setup failed: OpenGL Extension not supported.");
            m_bVBlankActive = false;
            return false;
        }

        glproc::SwapIntervalEXT(m_pDisplay, m_Drawable, rate);
        m_bVBlankActive = true;
        return true;

    } else {
        if (m_bVBlankActive) {
            glproc::SwapIntervalEXT(m_pDisplay, m_Drawable, 0);
            m_bVBlankActive = false;
        }
        return false;
    }
}

bool GLXContext::useDepthBuffer() const
{
    // NVidia GLX GLES doesn't allow framebuffer stencil without depth.
    return true;
}

void GLXContext::swapBuffers()
{
    glXSwapBuffers(m_pDisplay, m_Drawable);
}

bool GLXContext::haveARBCreateContext()
{
    static bool s_bExtensionChecked = false;
    static bool s_bHaveExtension = false;
    if (!s_bExtensionChecked) {
        s_bExtensionChecked = true;
        s_bHaveExtension = (queryGLXExtension("GLX_ARB_create_context"));
    }
    return s_bHaveExtension;
}

XVisualInfo* GLXContext::createDetachedContext(::Display* pDisplay, GLConfig& glConfig)
{
    m_pDisplay = pDisplay;
    GLXFBConfig fbConfig = getFBConfig(m_pDisplay, glConfig);
    XVisualInfo* pVisualInfo = glXGetVisualFromFBConfig(m_pDisplay, fbConfig);

    if (haveARBCreateContext()) {
        GLContextAttribs attrs;
        GLContextAttribs attrsWODebug;
        if (glConfig.m_bGLES) {
            attrs.append(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT);
            attrs.append(GLX_CONTEXT_MAJOR_VERSION_ARB, 2);
            attrs.append(GLX_CONTEXT_MINOR_VERSION_ARB, 0);
        }
        if (glConfig.m_bUseDebugContext) {
            attrsWODebug = attrs;
            attrs.append(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
        }
        PFNGLXCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB =
            (PFNGLXCREATECONTEXTATTRIBSARBPROC)
            getglXProcAddress("glXCreateContextAttribsARB");

        s_bDumpX11ErrorMsg = false;
        m_Context = CreateContextAttribsARB(m_pDisplay, fbConfig, 0, 1, attrs.get());
        s_bDumpX11ErrorMsg = true;
        if(!m_Context && glConfig.m_bUseDebugContext) {
            //On intel HW ContextCreation with DebugBit fails
            AVG_LOG_WARNING("Failed to create DEBUG context… falling back to standard context");
            s_bX11Error = false;
            m_Context = CreateContextAttribsARB(m_pDisplay, fbConfig, 0, 1, attrsWODebug.get());
            AVG_ASSERT(m_Context);
        }
        throwOnXError(AVG_ERR_DEBUG_CONTEXT_FAILED);
    } else {
        m_Context = glXCreateContext(m_pDisplay, pVisualInfo, 0, GL_TRUE);
    }
    AVG_ASSERT(m_Context);

    m_Colormap = XCreateColormap(pDisplay, RootWindow(m_pDisplay, pVisualInfo->screen),
            pVisualInfo->visual, AllocNone);
    AVG_ASSERT(m_Colormap);

    return pVisualInfo;
}

void GLXContext::setX11ErrorHandler()
{
    s_bDumpX11ErrorMsg = true;
    s_DefaultErrorHandler = XSetErrorHandler(X11ErrorHandler);
}

void GLXContext::resetX11ErrorHandler()
{
    XSetErrorHandler(s_DefaultErrorHandler);
}

void GLXContext::throwOnXError(int code)
{
    if (s_bX11Error) {
        throw Exception(code, "X error creating OpenGL context.");
    }
}

void GLXContext::initDrawable()
{
    m_Drawable = glXGetCurrentDrawable();
}

::GLXContext GLXContext::getGLXContext() const
{
    return m_Context;
}

::Display* GLXContext::getDisplay() const
{
    return m_pDisplay;
}

Colormap GLXContext::getColormap() const
{
    return m_Colormap;
}

GLXFBConfig GLXContext::getFBConfig(::Display* pDisplay, GLConfig& glConfig)
{
    GLContextAttribs attrs;
    attrs.append(GLX_X_RENDERABLE, 1);
    attrs.append(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
    attrs.append(GLX_RENDER_TYPE, GLX_RGBA_BIT);
    attrs.append(GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR);
    attrs.append(GLX_DEPTH_SIZE, 0);
    attrs.append(GLX_STENCIL_SIZE, 8);
    attrs.append(GLX_DOUBLEBUFFER, 1);
    attrs.append(GLX_RED_SIZE, 8);
    attrs.append(GLX_GREEN_SIZE, 8);
    attrs.append(GLX_BLUE_SIZE, 8);
    attrs.append(GLX_ALPHA_SIZE, 0);

    int fbCount;
    GLXFBConfig* pFBConfig = glXChooseFBConfig(m_pDisplay, DefaultScreen(m_pDisplay),
            attrs.get(), &fbCount);
    if (!pFBConfig) {
        throw Exception(AVG_ERR_UNSUPPORTED, "Creating OpenGL context failed.");
    }

    // Find the config with the appropriate number of multisample samples.
    int bestConfig = -1;
    int bestSamples = -1;
    int bestCaveat = std::numeric_limits<int>::max();
    for (int i=0; i<fbCount; ++i) {
        XVisualInfo* pVisualInfo = glXGetVisualFromFBConfig(m_pDisplay, pFBConfig[i]);
        if (pVisualInfo && pVisualInfo->depth == 24) {
            int numBuffers;
            int numSamples;
            int caveat;
            glXGetFBConfigAttrib(m_pDisplay, pFBConfig[i], GLX_SAMPLE_BUFFERS,
                    &numBuffers);
            glXGetFBConfigAttrib(m_pDisplay, pFBConfig[i], GLX_SAMPLES, &numSamples);
            glXGetFBConfigAttrib(m_pDisplay, pFBConfig[i], GLX_CONFIG_CAVEAT, &caveat);
            if (numSamples == 0) {
                // Configs without multisampling have numBuffers == 0 and numSamples == 0,
                // but the corresponding libavg config is multisamplesamples == 1.
                numSamples = 1;
            }
            if ((numSamples > bestSamples && numSamples <= glConfig.m_MultiSampleSamples)
                  || (numSamples == bestSamples && caveat < bestCaveat))
            {
                // A config is better than the last one in two cases:
                //    1) it has more samples per pixel (but not more than requested) or
                //    2) it has the same number of samples per pixel but a better caveat
                //       value.
                bestCaveat = caveat;
                bestConfig = i;
                bestSamples = numSamples;
            }
            XFree(pVisualInfo);
        }
    }
    glConfig.m_MultiSampleSamples = bestSamples;
    GLXFBConfig fbConfig = pFBConfig[bestConfig];
    XFree(pFBConfig);
    return fbConfig;
}

int GLXContext::X11ErrorHandler(::Display * pDisplay, XErrorEvent * pErrEvent)
{
    if (s_bDumpX11ErrorMsg) {
        char errorString[128];
        XGetErrorText(pDisplay, pErrEvent->error_code, errorString, 128);
        cerr << "X11 error creating GL context: " << errorString <<
            "\n\tMajor opcode of failed request: " << (int)(pErrEvent->request_code) <<
            "\n\tMinor opcode of failed request: " << (int)(pErrEvent->minor_code) <<
            "\n";
    }
    s_bX11Error = true;
    return 0;
}

}
<|endoftext|>


<commit_before>//      © Christian Sommerfeldt Øien
//      All rights reserved
#ifndef MODEL_HPP
#define MODEL_HPP

#include "sky.h"
struct photo;

#include <array>
#include <vector>
#include <variant>
#include <optional>
#include <functional>

namespace model {

using m3 = std::array<double, 9>;
using color = ::color;
using point = ::point;
using direction = ::direction;
inline point point_cast(direction d) { return ::point_from_origo(d); }
inline direction direction_cast(point p) { return ::direction_from_origo(p); }
struct rotation { direction axis; double angle; };
struct resolution { unsigned width; unsigned height; };
constexpr resolution hdtv{1920, 1080};
constexpr double pi{3.14159265358979};
constexpr double tau{pi * 2};
constexpr double linear(double a, double b, double u) { return a * (1 - u) + b * u; }
constexpr direction xd{1, 0, 0};
constexpr direction yd{0, 1, 0};
constexpr direction zd{0, 0, 1};
constexpr point o{0, 0, 0};
constexpr point xy(double x, double y) { return {x, y, 0}; }
constexpr point xz(double x, double z) { return {x, 0, z}; }
constexpr point yz(double y, double z) { return {0, y, z}; }
constexpr point onx(double k) { return {k, 0, 0}; }
constexpr point ony(double k) { return {0, k, 0}; }
constexpr point onz(double k) { return {0, 0, k}; }
constexpr color gray(double v) { return {v, v, v}; }
constexpr color red  {1, 0, 0};
constexpr color green{0, 1, 0};
constexpr color blue {0, 0, 1};
constexpr color white{1, 1, 1};
constexpr color black{0, 0, 0};
constexpr double water_ri{1.3};
constexpr double oil_ri{1.46};
constexpr double glass_ri{1.6};
constexpr double diamond_ri{2.4};
constexpr double silicon_ri{3.46};
constexpr double red_hue{0};
constexpr double yellow_hue{pi / 3};
constexpr double green_hue{tau / 3};
constexpr double blue_hue{2 * tau / 3};
constexpr double ultra_hue{tau};
color operator+(color p, color q);
color operator*(color p, color filter);
inline color operator*(color p, double u) { return p * gray(u); }
inline color from_hue(double h) { return from_hsv(h, 1, 1); }

direction operator*(direction, double);
direction operator-(direction);
direction operator+(direction a, direction b);
double operator*(direction a, direction b);
direction operator-(point to, point from);
point operator+(point, direction);
point & operator+=(point &, direction);
double abs(direction);
inline direction unit(direction d) { return d * (1 / abs(d)); }
direction xyc(double w);
direction xzc(double w);
direction yzc(double w);
inline double lin(double a, double b, double k) { return a * (1 - k) + b * k; }
inline color lin(color a, color b, double k) { return a * (1 - k) + b * k; }
inline point lin(point a, point b, double k)
{ return o + direction_cast(a) * (1 - k) + direction_cast(b) * k; }

void mov_(point & p, direction);
void mul_(direction & d, double);
void mul_(direction & d, m3);
void rot_(direction & d, rotation);
void rot_(point & p, point at, rotation);

struct plane {
    point p;
    direction d;
    void _mul(double);
    void _mov(direction offset);
    void _rot(point at, rotation);
};

struct sphere {
    point p;
    double r;
    void _mul(double);
    void _mov(direction offset);
    void _rot(point at, rotation);
};

struct common_geometric {
    point p;
    double r;
    direction d;
    void _mul(double);
    void _mov(direction offset);
    void _rot(point at, rotation);
};
struct cylinder : common_geometric {};
struct cone : common_geometric {};
struct parabol : common_geometric {};
struct hyperbol : common_geometric {
    double h;
    void _mul(double);
};
struct saddle {
    point p;
    direction d;
    direction x;
    double h;
    void _mul(double);
    void _mov(direction offset);
    void _rot(point at, rotation);
};

struct inv_shape {};
struct inv_plane : plane, inv_shape { inv_plane(point _p, direction _d); };
struct inv_sphere : sphere, inv_shape { inv_sphere(point _p, double _r); };
struct inv_cylinder : cylinder, inv_shape
{ inv_cylinder(point _p, double _r, direction _d); };
struct inv_cone : cone, inv_shape
{ inv_cone(point _p, double _r, direction _d); };
struct inv_parabol : parabol, inv_shape
{ inv_parabol(point _p, double _r, direction _d); };
struct inv_hyperbol : hyperbol, inv_shape
{ inv_hyperbol(point _p, double _r, direction _d, double _h); };
struct inv_saddle : saddle, inv_shape
{ inv_saddle(point _p, direction _d, direction _x, double _h); };

using shape = std::variant<
    plane, inv_plane,
    sphere, inv_sphere,
    cylinder, inv_cylinder,
    cone, inv_cone,
    hyperbol, inv_hyperbol,
    parabol, inv_parabol,
    saddle, inv_saddle>;

void mul_(shape & s, double);
void mov_(shape & s, direction offset);
void rot_(shape & s, point at, rotation);

struct observer {
    point e;
    point c;
    direction x;
};

struct surface {
    color reflection;
    color absorption;
    color refraction;
};

using str = std::string;

struct angular {
    direction d;
    direction x;
    double r;
    str n;
    surface s;
    void _mul(double);
    void _mov(direction);
    void _rot(point, rotation);
};

struct common_texture : common_geometric {
    direction x;
    str n;
    surface s;
};
struct planar : common_texture {};
struct planar1 : common_texture {};
struct relative : common_texture {};
struct axial : common_texture {};
struct axial1 : common_texture {};
using texture = std::variant<
    angular,
    planar, planar1,
    relative,
    axial, axial1>;
void mul_(texture & s, double);
void mov_(texture & s, direction offset);
void rot_(texture & s, point at, rotation);

struct optics {
    color reflection_filter;
    color absorption_filter;
    double refraction_index;
    color refraction_filter;
    color passthrough_filter;
};

using inter = std::vector<shape>;
void mul_(inter & s, point at, double);
void mov_(inter & s, direction offset);
void rot_(inter & s, point at, rotation);

using surface_f = std::function<surface(point, direction)>;

struct mapping_f
{
    point p;
    double r;
    direction d;
    direction x;
    surface_f f;
};
void mul_(mapping_f & m, point at, double);
void mov_(mapping_f & m, direction offset);
void rot_(mapping_f & m, point at, rotation);

using textmap = std::variant<texture, mapping_f>;

struct object {
    inter si;
    optics o;
    std::optional<textmap> u;
    object mul(point at, double);
    object mov(direction offset);
    object rot(point at, rotation);
};

struct light_spot {
    point p;
    color c;
};
using sky_f = std::function<color(direction)>;
struct world {
    observer obs;
    sky_f sky;
    std::vector<object> s;
    std::vector<light_spot> ls;
};
using world_gen_f = std::function<world(double)>;
void render(const world & w, std::string path, resolution, unsigned n_threads);
void sequence(world_gen_f wg, int nw, std::string path, resolution, unsigned n_threads);
void main(world_gen_f wg, int argc, char **argv);

class photo_base {
    photo * ph;
protected:
    color _get(real x, real y);
public:
    virtual ~photo_base();
    photo_base(std::string path);
    photo_base(const photo_base & other);
};

struct photo_sky : photo_base {
    using photo_base::photo_base;
    color operator()(direction d);
};

namespace /* model:: */ solids {

constexpr double g = 1.61803398875;  // golden-ratio
constexpr double g2 = 2.618033988750235;  // golden-ratio ^ 2
constexpr double g3 = 4.236067977500615;  // golden-ratio ^ 3

static inline direction mean(std::initializer_list<direction> list)
{
    point mean = o;
    for (direction d : list) {
        mean += d;
    }
    return direction_cast(mean) * (1.0 / list.size());
}

extern direction tetra_faces[4];
constexpr double tetra_mr = 1.7321;
constexpr double tetra_cr = 3;

extern direction cube_faces[6];
constexpr double cube_mr = 1.4142135623730951;
constexpr double cube_cr = 1.7320508075688772;

extern direction octa_faces[8];
constexpr double octa_mr = 1.2247448713915892;
constexpr double octa_cr = 1.7320508075688772;

extern direction dodeca_faces[12];
constexpr double dodeca_mr = 1.17557;
constexpr double dodeca_cr = 1.25841;

extern direction icosa_faces[20];
constexpr double icosa_mr = 1.07047;
constexpr double icosa_cr = 1.25841;

extern direction trunctetra_faces[8];
constexpr double trunctetra_cr = 1.9148542155126764;

extern direction truncocta_faces[14];
constexpr double truncocta_cr = 2; // todo

extern direction cubocta_faces[14];
constexpr double cubocta_cr = 1.4142135623730951;

extern direction trunccube_faces[14];
constexpr double trunccube_cr = 2; // todo

extern direction truncdodeca_faces[32];
constexpr double truncdodeca_cr = 2; // todo

extern direction icosadodeca_faces[32];
constexpr double icosadodeca_cr = 2; // todo

extern direction truncicosa_faces[32];
constexpr double truncicosa_cr = 2; // todo

} // solids
} // model
#endif
<commit_msg>complete with circumradii<commit_after>//      © Christian Sommerfeldt Øien
//      All rights reserved
#ifndef MODEL_HPP
#define MODEL_HPP

#include "sky.h"
struct photo;

#include <array>
#include <vector>
#include <variant>
#include <optional>
#include <functional>

namespace model {

using m3 = std::array<double, 9>;
using color = ::color;
using point = ::point;
using direction = ::direction;
inline point point_cast(direction d) { return ::point_from_origo(d); }
inline direction direction_cast(point p) { return ::direction_from_origo(p); }
struct rotation { direction axis; double angle; };
struct resolution { unsigned width; unsigned height; };
constexpr resolution hdtv{1920, 1080};
constexpr double pi{3.14159265358979};
constexpr double tau{pi * 2};
constexpr double linear(double a, double b, double u) { return a * (1 - u) + b * u; }
constexpr direction xd{1, 0, 0};
constexpr direction yd{0, 1, 0};
constexpr direction zd{0, 0, 1};
constexpr point o{0, 0, 0};
constexpr point xy(double x, double y) { return {x, y, 0}; }
constexpr point xz(double x, double z) { return {x, 0, z}; }
constexpr point yz(double y, double z) { return {0, y, z}; }
constexpr point onx(double k) { return {k, 0, 0}; }
constexpr point ony(double k) { return {0, k, 0}; }
constexpr point onz(double k) { return {0, 0, k}; }
constexpr color gray(double v) { return {v, v, v}; }
constexpr color red  {1, 0, 0};
constexpr color green{0, 1, 0};
constexpr color blue {0, 0, 1};
constexpr color white{1, 1, 1};
constexpr color black{0, 0, 0};
constexpr double water_ri{1.3};
constexpr double oil_ri{1.46};
constexpr double glass_ri{1.6};
constexpr double diamond_ri{2.4};
constexpr double silicon_ri{3.46};
constexpr double red_hue{0};
constexpr double yellow_hue{pi / 3};
constexpr double green_hue{tau / 3};
constexpr double blue_hue{2 * tau / 3};
constexpr double ultra_hue{tau};
color operator+(color p, color q);
color operator*(color p, color filter);
inline color operator*(color p, double u) { return p * gray(u); }
inline color from_hue(double h) { return from_hsv(h, 1, 1); }

direction operator*(direction, double);
direction operator-(direction);
direction operator+(direction a, direction b);
double operator*(direction a, direction b);
direction operator-(point to, point from);
point operator+(point, direction);
point & operator+=(point &, direction);
double abs(direction);
inline direction unit(direction d) { return d * (1 / abs(d)); }
direction xyc(double w);
direction xzc(double w);
direction yzc(double w);
inline double lin(double a, double b, double k) { return a * (1 - k) + b * k; }
inline color lin(color a, color b, double k) { return a * (1 - k) + b * k; }
inline point lin(point a, point b, double k)
{ return o + direction_cast(a) * (1 - k) + direction_cast(b) * k; }

void mov_(point & p, direction);
void mul_(direction & d, double);
void mul_(direction & d, m3);
void rot_(direction & d, rotation);
void rot_(point & p, point at, rotation);

struct plane {
    point p;
    direction d;
    void _mul(double);
    void _mov(direction offset);
    void _rot(point at, rotation);
};

struct sphere {
    point p;
    double r;
    void _mul(double);
    void _mov(direction offset);
    void _rot(point at, rotation);
};

struct common_geometric {
    point p;
    double r;
    direction d;
    void _mul(double);
    void _mov(direction offset);
    void _rot(point at, rotation);
};
struct cylinder : common_geometric {};
struct cone : common_geometric {};
struct parabol : common_geometric {};
struct hyperbol : common_geometric {
    double h;
    void _mul(double);
};
struct saddle {
    point p;
    direction d;
    direction x;
    double h;
    void _mul(double);
    void _mov(direction offset);
    void _rot(point at, rotation);
};

struct inv_shape {};
struct inv_plane : plane, inv_shape { inv_plane(point _p, direction _d); };
struct inv_sphere : sphere, inv_shape { inv_sphere(point _p, double _r); };
struct inv_cylinder : cylinder, inv_shape
{ inv_cylinder(point _p, double _r, direction _d); };
struct inv_cone : cone, inv_shape
{ inv_cone(point _p, double _r, direction _d); };
struct inv_parabol : parabol, inv_shape
{ inv_parabol(point _p, double _r, direction _d); };
struct inv_hyperbol : hyperbol, inv_shape
{ inv_hyperbol(point _p, double _r, direction _d, double _h); };
struct inv_saddle : saddle, inv_shape
{ inv_saddle(point _p, direction _d, direction _x, double _h); };

using shape = std::variant<
    plane, inv_plane,
    sphere, inv_sphere,
    cylinder, inv_cylinder,
    cone, inv_cone,
    hyperbol, inv_hyperbol,
    parabol, inv_parabol,
    saddle, inv_saddle>;

void mul_(shape & s, double);
void mov_(shape & s, direction offset);
void rot_(shape & s, point at, rotation);

struct observer {
    point e;
    point c;
    direction x;
};

struct surface {
    color reflection;
    color absorption;
    color refraction;
};

using str = std::string;

struct angular {
    direction d;
    direction x;
    double r;
    str n;
    surface s;
    void _mul(double);
    void _mov(direction);
    void _rot(point, rotation);
};

struct common_texture : common_geometric {
    direction x;
    str n;
    surface s;
};
struct planar : common_texture {};
struct planar1 : common_texture {};
struct relative : common_texture {};
struct axial : common_texture {};
struct axial1 : common_texture {};
using texture = std::variant<
    angular,
    planar, planar1,
    relative,
    axial, axial1>;
void mul_(texture & s, double);
void mov_(texture & s, direction offset);
void rot_(texture & s, point at, rotation);

struct optics {
    color reflection_filter;
    color absorption_filter;
    double refraction_index;
    color refraction_filter;
    color passthrough_filter;
};

using inter = std::vector<shape>;
void mul_(inter & s, point at, double);
void mov_(inter & s, direction offset);
void rot_(inter & s, point at, rotation);

using surface_f = std::function<surface(point, direction)>;

struct mapping_f
{
    point p;
    double r;
    direction d;
    direction x;
    surface_f f;
};
void mul_(mapping_f & m, point at, double);
void mov_(mapping_f & m, direction offset);
void rot_(mapping_f & m, point at, rotation);

using textmap = std::variant<texture, mapping_f>;

struct object {
    inter si;
    optics o;
    std::optional<textmap> u;
    object mul(point at, double);
    object mov(direction offset);
    object rot(point at, rotation);
};

struct light_spot {
    point p;
    color c;
};
using sky_f = std::function<color(direction)>;
struct world {
    observer obs;
    sky_f sky;
    std::vector<object> s;
    std::vector<light_spot> ls;
};
using world_gen_f = std::function<world(double)>;
void render(const world & w, std::string path, resolution, unsigned n_threads);
void sequence(world_gen_f wg, int nw, std::string path, resolution, unsigned n_threads);
void main(world_gen_f wg, int argc, char **argv);

class photo_base {
    photo * ph;
protected:
    color _get(real x, real y);
public:
    virtual ~photo_base();
    photo_base(std::string path);
    photo_base(const photo_base & other);
};

struct photo_sky : photo_base {
    using photo_base::photo_base;
    color operator()(direction d);
};

namespace /* model:: */ solids {

constexpr double g = 1.61803398875;  // golden-ratio
constexpr double g2 = 2.618033988750235;  // golden-ratio ^ 2
constexpr double g3 = 4.236067977500615;  // golden-ratio ^ 3

static inline direction mean(std::initializer_list<direction> list)
{
    point mean = o;
    for (direction d : list) {
        mean += d;
    }
    return direction_cast(mean) * (1.0 / list.size());
}

extern direction tetra_faces[4];
constexpr double tetra_mr = 1.7320508075688772;
constexpr double tetra_cr = 3;

extern direction cube_faces[6];
constexpr double cube_mr = 1.4142135623730951;
constexpr double cube_cr = 1.7320508075688772;

extern direction octa_faces[8];
constexpr double octa_mr = 1.2247448713915892;
constexpr double octa_cr = 1.7320508075688772;

extern direction dodeca_faces[12];
constexpr double dodeca_mr = 1.1755705045849463;
constexpr double dodeca_cr = 1.258408572364819;

extern direction icosa_faces[20];
constexpr double icosa_mr = 1.07046626931927;
constexpr double icosa_cr = 1.258408572364819;

extern direction trunctetra_faces[8];
constexpr double trunctetra_cr = 1.9148542155126764;

extern direction truncocta_faces[14];
constexpr double truncocta_cr = 1.2909938468095037;

extern direction cubocta_faces[14];
constexpr double cubocta_cr = 1.4142135623730951;

extern direction trunccube_faces[14];
constexpr double trunccube_cr = 1.082392200292394;

extern direction truncdodeca_faces[32];
constexpr double truncdodeca_cr = 1.0929472010050334;

extern direction icosadodeca_faces[32];
constexpr double icosadodeca_cr = 1.1755743793385014;

extern direction truncicosa_faces[32];
constexpr double truncicosa_cr = 1.1940511957861941;

} // solids
} // model
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2014-2017 The Dash Core developers
// Copyright (c) 2017-2018 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <activemasternode.h>
#include <masternodesync.h>
#include <masternodeman.h>
#include <masternodepayments.h>
#include <netbase.h>
#include <protocol.h>
#include <script/standard.h>
#include <net.h>
// Keep track of the active Masternode
CActiveMasternode activeMasternode;

void CActiveMasternode::ManageState(CConnman& connman)
{
    LogPrint(BCLog::MN, "CActiveMasternode::ManageState -- Start\n");
    if(!fMasternodeMode) {
        LogPrint(BCLog::MN, "CActiveMasternode::ManageState -- Not a masternode, returning\n");
        return;
    }
    if(Params().NetworkIDString() != CBaseChainParams::REGTEST && !masternodeSync.IsBlockchainSynced()) {
        LogPrint(BCLog::MN, "CActiveMasternode::ManageState -- %s: %s\n", GetStateString(), GetStatus());
        return;
    }

    if(nState == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) {
        nState = ACTIVE_MASTERNODE_INITIAL;
    }

    LogPrint(BCLog::MN, "CActiveMasternode::ManageState -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);

    if(eType == MASTERNODE_UNKNOWN) {
        ManageStateInitial(connman);
    }

    if(eType == MASTERNODE_REMOTE) {
        ManageStateRemote();
    }
    SendMasternodePing(connman);
}

std::string CActiveMasternode::GetStateString() const
{
    switch (nState) {
        case ACTIVE_MASTERNODE_INITIAL:         return "INITIAL";
        case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "SYNC_IN_PROCESS";
        case ACTIVE_MASTERNODE_INPUT_TOO_NEW:   return "INPUT_TOO_NEW";
        case ACTIVE_MASTERNODE_NOT_CAPABLE:     return "NOT_CAPABLE";
        case ACTIVE_MASTERNODE_STARTED:         return "STARTED";
        default:                                return "UNKNOWN";
    }
}

std::string CActiveMasternode::GetStatus() const
{
    switch (nState) {
        case ACTIVE_MASTERNODE_INITIAL:         return "Node just started, not yet activated";
        case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Masternode";
        case ACTIVE_MASTERNODE_INPUT_TOO_NEW:   return strprintf("Masternode input must have at least %d confirmations", Params().GetConsensus().nMasternodeMinimumConfirmations);
        case ACTIVE_MASTERNODE_NOT_CAPABLE:     return "Not capable masternode: " + strNotCapableReason;
        case ACTIVE_MASTERNODE_STARTED:         return "Masternode successfully started";
        default:                                return "Unknown";
    }
}

std::string CActiveMasternode::GetTypeString() const
{
    std::string strType;
    switch(eType) {
    case MASTERNODE_REMOTE:
        strType = "REMOTE";
        break;
    default:
        strType = "UNKNOWN";
        break;
    }
    return strType;
}

bool CActiveMasternode::SendMasternodePing(CConnman& connman)
{
    if(!fPingerEnabled) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- %s: masternode ping service is disabled, skipping...\n", GetStateString());
        return false;
    }

    if(!mnodeman.Has(outpoint)) {
        strNotCapableReason = "Masternode not in masternode list";
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- %s: %s\n", GetStateString(), strNotCapableReason);
        return false;
    }
    bool bPoSeMetric = (rand()%100) > 20;
    CMasternodePing mnp(outpoint);
    const CMasternode* pmn = mnodeman.Find(outpoint);
    mnp.nSentinelVersion = nSentinelVersion;
    mnp.fSentinelIsCurrent =
            (abs(GetAdjustedTime() - nSentinelPingTime) < MASTERNODE_SENTINEL_PING_MAX_SECONDS);
    if(!mnp.Sign(keyMasternode, pubKeyMasternode)) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- ERROR: Couldn't sign Masternode Ping\n");
        return false;
    }

    // Update lastPing for our masternode in Masternode list
    if(mnodeman.IsMasternodePingedWithin(pmn, outpoint, MASTERNODE_MIN_MNP_SECONDS, mnp.sigTime)) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Too early to send Masternode Ping\n");
        return false;
    }
    if(pmn->nActiveState == MASTERNODE_PRE_ENABLED || !masternodeSync.IsSynced()) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Active masternode is not ready to start sending pings\n");
        return false;
    }
    if(pmn->nActiveState != MASTERNODE_ENABLED) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Active masternode is not enabled so it cannot send pings\n");
        return false;
    }
    // ensure that we should only create ping if in the winners list
    const CScript &mnpayee = GetScriptForDestination(PKHash(pmn->pubKeyCollateralAddress));
    bool foundPayee = false;
    {
        LOCK(cs_mapMasternodeBlocks);
        CMasternodePayee payee;
        // only allow ping if MNPAYMENTS_SIGNATURES_REQUIRED votes are on this masternode in last 10 blocks of winners list and 20 blocks into future (match default of masternode winners)
        for (int i = -10; i < 20; i++) {
            if(mnpayments.mapMasternodeBlocks.count(::ChainActive().Height()+i) &&
                  mnpayments.mapMasternodeBlocks[::ChainActive().Height()+i].HasPayeeWithVotes(mnpayee, MNPAYMENTS_SIGNATURES_REQUIRED, payee))
            {
                foundPayee = true;
                break;
            }
        }
    }
    if(!foundPayee){
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Not in winners list, skipping ping...\n");
        return false;
    }
    if(bb && bPoSeMetric)
        return true;
    mnodeman.SetMasternodeLastPing(outpoint, mnp);

    LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Relaying ping, collateral=%s\n", outpoint.ToStringShort());
    mnp.Relay(connman);

    return true;
}

bool CActiveMasternode::UpdateSentinelPing(int version)
{

    nSentinelVersion = version;
    nSentinelPingTime = GetAdjustedTime();

    return true;
}

void CActiveMasternode::ManageStateInitial(CConnman& connman)
{
    LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);

    // Check that our local network configuration is correct
    if (!fListen) {
        // listen option is probably overwritten by smth else, no good
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Masternode must accept connections from outside. Make sure listen configuration option is not overwritten by some another parameter.";
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // First try to find whatever local address is specified by externalip option
    bool fFoundLocal = GetLocal(service) && CMasternode::IsValidNetAddr(service);
    if(!fFoundLocal) {
        bool empty = true;
        // If we have some peers, let's try to find our local address from one of them
        connman.ForEachNodeContinueIf(CConnman::AllNodes, [&fFoundLocal, &empty, this](CNode* pnode) {
            empty = false;
            if (pnode->addr.IsIPv4())
                fFoundLocal = GetLocal(service, &pnode->addr) && CMasternode::IsValidNetAddr(service);
            return !fFoundLocal;
        });
        // nothing and no live connections, can't do anything for now
        if (empty) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Can't detect valid external address. Will retry when there are some connections available.";
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
    }

    if(!fFoundLocal) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Can't detect valid external address. Please consider using the externalip configuration option if problem persists. Make sure to use IPv4 address only.";
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }
    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
    int mainnetDefaultPort = chainParams->GetDefaultPort();
    if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
        if(service.GetPort() != mainnetDefaultPort) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort);
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
    } else if(service.GetPort() == mainnetDefaultPort) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort);
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // Check socket connectivity
    LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- Checking inbound connection to '%s'\n", service.ToString());
    SOCKET hSocket = INVALID_SOCKET;
    hSocket = CreateSocket(service);
    if (hSocket == INVALID_SOCKET) {
         LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- Could not create socket '%s'\n", service.ToString());
         return;
    }
    bool fConnected = ConnectSocketDirectly(service, hSocket, nConnectTimeout, true) && IsSelectableSocket(hSocket);
    CloseSocket(hSocket);

    if (!fConnected) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Could not connect to " + service.ToString();
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // Default to REMOTE
    eType = MASTERNODE_REMOTE;

    LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- End status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
}

void CActiveMasternode::ManageStateRemote()
{
    LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, pubKeyMasternode.GetID() = %s\n",
             GetStatus(), GetTypeString(), fPingerEnabled, pubKeyMasternode.GetID().ToString());

    mnodeman.CheckMasternode(pubKeyMasternode, true);
    masternode_info_t infoMn;
    if(mnodeman.GetMasternodeInfo(pubKeyMasternode, infoMn)) {
        if(infoMn.nProtocolVersion != MIN_PEER_PROTO_VERSION) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Invalid protocol version";
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(service != infoMn.addr) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Broadcasted IP doesn't match our external address. Make sure you issued a new broadcast if IP of this masternode changed recently.";
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(!CMasternode::IsValidStateForAutoStart(infoMn.nActiveState)) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = strprintf("Masternode in %s state", CMasternode::StateToString(infoMn.nActiveState));
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(nState != ACTIVE_MASTERNODE_STARTED) {
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- STARTED!\n");
            outpoint = infoMn.outpoint;
            service = infoMn.addr;
            fPingerEnabled = true;
            nState = ACTIVE_MASTERNODE_STARTED;
        }
    }
    else {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Masternode not in masternode list";
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
    }
}
<commit_msg>remove net.h from cpp file not needed<commit_after>// Copyright (c) 2014-2017 The Dash Core developers
// Copyright (c) 2017-2018 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <activemasternode.h>
#include <masternodesync.h>
#include <masternodeman.h>
#include <masternodepayments.h>
#include <netbase.h>
#include <protocol.h>
#include <script/standard.h>
// Keep track of the active Masternode
CActiveMasternode activeMasternode;

void CActiveMasternode::ManageState(CConnman& connman)
{
    LogPrint(BCLog::MN, "CActiveMasternode::ManageState -- Start\n");
    if(!fMasternodeMode) {
        LogPrint(BCLog::MN, "CActiveMasternode::ManageState -- Not a masternode, returning\n");
        return;
    }
    if(Params().NetworkIDString() != CBaseChainParams::REGTEST && !masternodeSync.IsBlockchainSynced()) {
        LogPrint(BCLog::MN, "CActiveMasternode::ManageState -- %s: %s\n", GetStateString(), GetStatus());
        return;
    }

    if(nState == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) {
        nState = ACTIVE_MASTERNODE_INITIAL;
    }

    LogPrint(BCLog::MN, "CActiveMasternode::ManageState -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);

    if(eType == MASTERNODE_UNKNOWN) {
        ManageStateInitial(connman);
    }

    if(eType == MASTERNODE_REMOTE) {
        ManageStateRemote();
    }
    SendMasternodePing(connman);
}

std::string CActiveMasternode::GetStateString() const
{
    switch (nState) {
        case ACTIVE_MASTERNODE_INITIAL:         return "INITIAL";
        case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "SYNC_IN_PROCESS";
        case ACTIVE_MASTERNODE_INPUT_TOO_NEW:   return "INPUT_TOO_NEW";
        case ACTIVE_MASTERNODE_NOT_CAPABLE:     return "NOT_CAPABLE";
        case ACTIVE_MASTERNODE_STARTED:         return "STARTED";
        default:                                return "UNKNOWN";
    }
}

std::string CActiveMasternode::GetStatus() const
{
    switch (nState) {
        case ACTIVE_MASTERNODE_INITIAL:         return "Node just started, not yet activated";
        case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Masternode";
        case ACTIVE_MASTERNODE_INPUT_TOO_NEW:   return strprintf("Masternode input must have at least %d confirmations", Params().GetConsensus().nMasternodeMinimumConfirmations);
        case ACTIVE_MASTERNODE_NOT_CAPABLE:     return "Not capable masternode: " + strNotCapableReason;
        case ACTIVE_MASTERNODE_STARTED:         return "Masternode successfully started";
        default:                                return "Unknown";
    }
}

std::string CActiveMasternode::GetTypeString() const
{
    std::string strType;
    switch(eType) {
    case MASTERNODE_REMOTE:
        strType = "REMOTE";
        break;
    default:
        strType = "UNKNOWN";
        break;
    }
    return strType;
}

bool CActiveMasternode::SendMasternodePing(CConnman& connman)
{
    if(!fPingerEnabled) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- %s: masternode ping service is disabled, skipping...\n", GetStateString());
        return false;
    }

    if(!mnodeman.Has(outpoint)) {
        strNotCapableReason = "Masternode not in masternode list";
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- %s: %s\n", GetStateString(), strNotCapableReason);
        return false;
    }
    bool bPoSeMetric = (rand()%100) > 20;
    CMasternodePing mnp(outpoint);
    const CMasternode* pmn = mnodeman.Find(outpoint);
    mnp.nSentinelVersion = nSentinelVersion;
    mnp.fSentinelIsCurrent =
            (abs(GetAdjustedTime() - nSentinelPingTime) < MASTERNODE_SENTINEL_PING_MAX_SECONDS);
    if(!mnp.Sign(keyMasternode, pubKeyMasternode)) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- ERROR: Couldn't sign Masternode Ping\n");
        return false;
    }

    // Update lastPing for our masternode in Masternode list
    if(mnodeman.IsMasternodePingedWithin(pmn, outpoint, MASTERNODE_MIN_MNP_SECONDS, mnp.sigTime)) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Too early to send Masternode Ping\n");
        return false;
    }
    if(pmn->nActiveState == MASTERNODE_PRE_ENABLED || !masternodeSync.IsSynced()) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Active masternode is not ready to start sending pings\n");
        return false;
    }
    if(pmn->nActiveState != MASTERNODE_ENABLED) {
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Active masternode is not enabled so it cannot send pings\n");
        return false;
    }
    // ensure that we should only create ping if in the winners list
    const CScript &mnpayee = GetScriptForDestination(PKHash(pmn->pubKeyCollateralAddress));
    bool foundPayee = false;
    {
        LOCK(cs_mapMasternodeBlocks);
        CMasternodePayee payee;
        // only allow ping if MNPAYMENTS_SIGNATURES_REQUIRED votes are on this masternode in last 10 blocks of winners list and 20 blocks into future (match default of masternode winners)
        for (int i = -10; i < 20; i++) {
            if(mnpayments.mapMasternodeBlocks.count(::ChainActive().Height()+i) &&
                  mnpayments.mapMasternodeBlocks[::ChainActive().Height()+i].HasPayeeWithVotes(mnpayee, MNPAYMENTS_SIGNATURES_REQUIRED, payee))
            {
                foundPayee = true;
                break;
            }
        }
    }
    if(!foundPayee){
        LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Not in winners list, skipping ping...\n");
        return false;
    }
    if(bb && bPoSeMetric)
        return true;
    mnodeman.SetMasternodeLastPing(outpoint, mnp);

    LogPrint(BCLog::MN, "CActiveMasternode::SendMasternodePing -- Relaying ping, collateral=%s\n", outpoint.ToStringShort());
    mnp.Relay(connman);

    return true;
}

bool CActiveMasternode::UpdateSentinelPing(int version)
{

    nSentinelVersion = version;
    nSentinelPingTime = GetAdjustedTime();

    return true;
}

void CActiveMasternode::ManageStateInitial(CConnman& connman)
{
    LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);

    // Check that our local network configuration is correct
    if (!fListen) {
        // listen option is probably overwritten by smth else, no good
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Masternode must accept connections from outside. Make sure listen configuration option is not overwritten by some another parameter.";
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // First try to find whatever local address is specified by externalip option
    bool fFoundLocal = GetLocal(service) && CMasternode::IsValidNetAddr(service);
    if(!fFoundLocal) {
        bool empty = true;
        // If we have some peers, let's try to find our local address from one of them
        connman.ForEachNodeContinueIf(CConnman::AllNodes, [&fFoundLocal, &empty, this](CNode* pnode) {
            empty = false;
            if (pnode->addr.IsIPv4())
                fFoundLocal = GetLocal(service, &pnode->addr) && CMasternode::IsValidNetAddr(service);
            return !fFoundLocal;
        });
        // nothing and no live connections, can't do anything for now
        if (empty) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Can't detect valid external address. Will retry when there are some connections available.";
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
    }

    if(!fFoundLocal) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Can't detect valid external address. Please consider using the externalip configuration option if problem persists. Make sure to use IPv4 address only.";
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }
    const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
    int mainnetDefaultPort = chainParams->GetDefaultPort();
    if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
        if(service.GetPort() != mainnetDefaultPort) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort);
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
    } else if(service.GetPort() == mainnetDefaultPort) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort);
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // Check socket connectivity
    LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- Checking inbound connection to '%s'\n", service.ToString());
    SOCKET hSocket = INVALID_SOCKET;
    hSocket = CreateSocket(service);
    if (hSocket == INVALID_SOCKET) {
         LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- Could not create socket '%s'\n", service.ToString());
         return;
    }
    bool fConnected = ConnectSocketDirectly(service, hSocket, nConnectTimeout, true) && IsSelectableSocket(hSocket);
    CloseSocket(hSocket);

    if (!fConnected) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Could not connect to " + service.ToString();
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // Default to REMOTE
    eType = MASTERNODE_REMOTE;

    LogPrint(BCLog::MN, "CActiveMasternode::ManageStateInitial -- End status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
}

void CActiveMasternode::ManageStateRemote()
{
    LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, pubKeyMasternode.GetID() = %s\n",
             GetStatus(), GetTypeString(), fPingerEnabled, pubKeyMasternode.GetID().ToString());

    mnodeman.CheckMasternode(pubKeyMasternode, true);
    masternode_info_t infoMn;
    if(mnodeman.GetMasternodeInfo(pubKeyMasternode, infoMn)) {
        if(infoMn.nProtocolVersion != MIN_PEER_PROTO_VERSION) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Invalid protocol version";
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(service != infoMn.addr) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Broadcasted IP doesn't match our external address. Make sure you issued a new broadcast if IP of this masternode changed recently.";
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(!CMasternode::IsValidStateForAutoStart(infoMn.nActiveState)) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = strprintf("Masternode in %s state", CMasternode::StateToString(infoMn.nActiveState));
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(nState != ACTIVE_MASTERNODE_STARTED) {
            LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- STARTED!\n");
            outpoint = infoMn.outpoint;
            service = infoMn.addr;
            fPingerEnabled = true;
            nState = ACTIVE_MASTERNODE_STARTED;
        }
    }
    else {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Masternode not in masternode list";
        LogPrint(BCLog::MN, "CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
    }
}
<|endoftext|>


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

#include "base/test/test_timeouts.h"

#include <algorithm>

#include "base/command_line.h"
#include "base/debug/debugger.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/test_switches.h"

namespace {

// ASan and TSan instrument each memory access. This may slow the execution
// down significantly.
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || defined(SYZYASAN)
static const int kTimeoutMultiplier = 2;
#else
static const int kTimeoutMultiplier = 1;
#endif

const int kAlmostInfiniteTimeoutMs = 100000000;

// Sets value to the greatest of:
// 1) value's current value multiplied by kTimeoutMultiplier (assuming
// InitializeTimeout is called only once per value).
// 2) min_value.
// 3) the numerical value given by switch_name on the command line multiplied
// by kTimeoutMultiplier.
void InitializeTimeout(const char* switch_name, int min_value, int* value) {
  DCHECK(value);
  if (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
    std::string string_value(
        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name));
    int timeout;
    base::StringToInt(string_value, &timeout);
    *value = std::max(*value, timeout);
  }
  *value *= kTimeoutMultiplier;
  *value = std::max(*value, min_value);
}

// Sets value to the greatest of:
// 1) value's current value multiplied by kTimeoutMultiplier.
// 2) 0
// 3) the numerical value given by switch_name on the command line multiplied
// by kTimeoutMultiplier.
void InitializeTimeout(const char* switch_name, int* value) {
  InitializeTimeout(switch_name, 0, value);
}

}  // namespace

// static
bool TestTimeouts::initialized_ = false;

// The timeout values should increase in the order they appear in this block.
// static
int TestTimeouts::tiny_timeout_ms_ = 100;
int TestTimeouts::action_timeout_ms_ = 10000;
#ifndef NDEBUG
int TestTimeouts::action_max_timeout_ms_ = 45000;
#else
int TestTimeouts::action_max_timeout_ms_ = 30000;
#endif  // NDEBUG
int TestTimeouts::large_test_timeout_ms_ = 10 * 60 * 1000;

int TestTimeouts::test_launcher_timeout_ms_ = 45000;

// static
void TestTimeouts::Initialize() {
  if (initialized_) {
    NOTREACHED();
    return;
  }
  initialized_ = true;

  if (base::debug::BeingDebugged()) {
    fprintf(stdout,
        "Detected presence of a debugger, running without test timeouts.\n");
  }

  // Note that these timeouts MUST be initialized in the correct order as
  // per the CHECKS below.
  InitializeTimeout(switches::kTestTinyTimeout, &tiny_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionTimeout,
                    base::debug::BeingDebugged() ? kAlmostInfiniteTimeoutMs
                                                 : tiny_timeout_ms_,
                    &action_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_,
                    &action_max_timeout_ms_);
  InitializeTimeout(switches::kTestLargeTimeout, action_max_timeout_ms_,
                    &large_test_timeout_ms_);

  // Test launcher timeout is independent from anything above action timeout.
  InitializeTimeout(switches::kTestLauncherTimeout, action_timeout_ms_,
                    &test_launcher_timeout_ms_);

  // The timeout values should be increasing in the right order.
  CHECK(tiny_timeout_ms_ <= action_timeout_ms_);
  CHECK(action_timeout_ms_ <= action_max_timeout_ms_);
  CHECK(action_max_timeout_ms_ <= large_test_timeout_ms_);

  CHECK(action_timeout_ms_ <= test_launcher_timeout_ms_);
}
<commit_msg>Increase test timeouts under MSan.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/test/test_timeouts.h"

#include <algorithm>

#include "base/command_line.h"
#include "base/debug/debugger.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/test_switches.h"

namespace {

// ASan/TSan/MSan instrument each memory access. This may slow the execution
// down significantly.
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
    defined(SYZYASAN) || defined(MEMORY_SANITIZER)
static const int kTimeoutMultiplier = 2;
#else
static const int kTimeoutMultiplier = 1;
#endif

const int kAlmostInfiniteTimeoutMs = 100000000;

// Sets value to the greatest of:
// 1) value's current value multiplied by kTimeoutMultiplier (assuming
// InitializeTimeout is called only once per value).
// 2) min_value.
// 3) the numerical value given by switch_name on the command line multiplied
// by kTimeoutMultiplier.
void InitializeTimeout(const char* switch_name, int min_value, int* value) {
  DCHECK(value);
  if (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
    std::string string_value(
        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name));
    int timeout;
    base::StringToInt(string_value, &timeout);
    *value = std::max(*value, timeout);
  }
  *value *= kTimeoutMultiplier;
  *value = std::max(*value, min_value);
}

// Sets value to the greatest of:
// 1) value's current value multiplied by kTimeoutMultiplier.
// 2) 0
// 3) the numerical value given by switch_name on the command line multiplied
// by kTimeoutMultiplier.
void InitializeTimeout(const char* switch_name, int* value) {
  InitializeTimeout(switch_name, 0, value);
}

}  // namespace

// static
bool TestTimeouts::initialized_ = false;

// The timeout values should increase in the order they appear in this block.
// static
int TestTimeouts::tiny_timeout_ms_ = 100;
int TestTimeouts::action_timeout_ms_ = 10000;
#ifndef NDEBUG
int TestTimeouts::action_max_timeout_ms_ = 45000;
#else
int TestTimeouts::action_max_timeout_ms_ = 30000;
#endif  // NDEBUG
int TestTimeouts::large_test_timeout_ms_ = 10 * 60 * 1000;

int TestTimeouts::test_launcher_timeout_ms_ = 45000;

// static
void TestTimeouts::Initialize() {
  if (initialized_) {
    NOTREACHED();
    return;
  }
  initialized_ = true;

  if (base::debug::BeingDebugged()) {
    fprintf(stdout,
        "Detected presence of a debugger, running without test timeouts.\n");
  }

  // Note that these timeouts MUST be initialized in the correct order as
  // per the CHECKS below.
  InitializeTimeout(switches::kTestTinyTimeout, &tiny_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionTimeout,
                    base::debug::BeingDebugged() ? kAlmostInfiniteTimeoutMs
                                                 : tiny_timeout_ms_,
                    &action_timeout_ms_);
  InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_,
                    &action_max_timeout_ms_);
  InitializeTimeout(switches::kTestLargeTimeout, action_max_timeout_ms_,
                    &large_test_timeout_ms_);

  // Test launcher timeout is independent from anything above action timeout.
  InitializeTimeout(switches::kTestLauncherTimeout, action_timeout_ms_,
                    &test_launcher_timeout_ms_);

  // The timeout values should be increasing in the right order.
  CHECK(tiny_timeout_ms_ <= action_timeout_ms_);
  CHECK(action_timeout_ms_ <= action_max_timeout_ms_);
  CHECK(action_max_timeout_ms_ <= large_test_timeout_ms_);

  CHECK(action_timeout_ms_ <= test_launcher_timeout_ms_);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: listenercalls.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-23 13:10:18 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifdef PCH
#include "ui_pch.hxx"
#endif

#pragma hdrstop

#include <com/sun/star/util/XModifyListener.hpp>
#include <tools/debug.hxx>

#include "listenercalls.hxx"

using namespace com::sun::star;

//------------------------------------------------------------------------

ScUnoListenerCalls::ScUnoListenerCalls()
{
}

ScUnoListenerCalls::~ScUnoListenerCalls()
{
    DBG_ASSERT( aEntries.empty(), "unhandled listener calls remaining" );
}

void ScUnoListenerCalls::Add( const uno::Reference<util::XModifyListener>& rListener,
                                const lang::EventObject& rEvent )
{
    if ( rListener.is() )
        aEntries.push_back( ScUnoListenerEntry( rListener, rEvent ) );
}

void ScUnoListenerCalls::ExecuteAndClear()
{
    //  Execute all stored calls and remove them from the list.
    //  During each modified() call, Add may be called again.
    //  These new calls are executed here, too.

    if (!aEntries.empty())
    {
        std::list<ScUnoListenerEntry>::iterator aItr(aEntries.begin());
        std::list<ScUnoListenerEntry>::iterator aEndItr(aEntries.end());
        while ( aItr != aEndItr )
        {
            ScUnoListenerEntry aEntry = *aItr;
            try
            {
                aEntry.xListener->modified( aEntry.aEvent );
            }
            catch ( uno::RuntimeException )
            {
                // the listener is an external object and may throw a RuntimeException
                // for reasons we don't know
            }

            //  New calls that are added during the modified() call are appended to the end
            //  of aEntries, so the loop will catch them, too (as long as erase happens
            //  after modified).

            aItr = aEntries.erase(aItr);
        }
    }
}

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.116); FILE MERGED 2005/09/05 15:08:57 rt 1.3.116.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: listenercalls.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 22:47:44 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifdef PCH
#include "ui_pch.hxx"
#endif

#pragma hdrstop

#include <com/sun/star/util/XModifyListener.hpp>
#include <tools/debug.hxx>

#include "listenercalls.hxx"

using namespace com::sun::star;

//------------------------------------------------------------------------

ScUnoListenerCalls::ScUnoListenerCalls()
{
}

ScUnoListenerCalls::~ScUnoListenerCalls()
{
    DBG_ASSERT( aEntries.empty(), "unhandled listener calls remaining" );
}

void ScUnoListenerCalls::Add( const uno::Reference<util::XModifyListener>& rListener,
                                const lang::EventObject& rEvent )
{
    if ( rListener.is() )
        aEntries.push_back( ScUnoListenerEntry( rListener, rEvent ) );
}

void ScUnoListenerCalls::ExecuteAndClear()
{
    //  Execute all stored calls and remove them from the list.
    //  During each modified() call, Add may be called again.
    //  These new calls are executed here, too.

    if (!aEntries.empty())
    {
        std::list<ScUnoListenerEntry>::iterator aItr(aEntries.begin());
        std::list<ScUnoListenerEntry>::iterator aEndItr(aEntries.end());
        while ( aItr != aEndItr )
        {
            ScUnoListenerEntry aEntry = *aItr;
            try
            {
                aEntry.xListener->modified( aEntry.aEvent );
            }
            catch ( uno::RuntimeException )
            {
                // the listener is an external object and may throw a RuntimeException
                // for reasons we don't know
            }

            //  New calls that are added during the modified() call are appended to the end
            //  of aEntries, so the loop will catch them, too (as long as erase happens
            //  after modified).

            aItr = aEntries.erase(aItr);
        }
    }
}

<|endoftext|>


<commit_before>/**
 * \file
 * \brief CallOnceOperationsTestCase class implementation
 *
 * \author Copyright (C) 2015-2017 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * 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 "CallOnceOperationsTestCase.hpp"

#include "SequenceAsserter.hpp"
#include "wasteTime.hpp"

#include "distortos/callOnce.hpp"
#include "distortos/DynamicThread.hpp"
#include "distortos/statistics.hpp"
#include "distortos/ThisThread.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// sleepFor() duration used in function() passed to callOnce()
constexpr auto sleepForDuration = TickClock::duration{10};

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {512};

/// number of test threads
constexpr size_t totalThreads {8};

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// pair of sequence points
using SequencePoints = std::pair<unsigned int, unsigned int>;

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Test function passed to callOnce().
 *
 * This function marks first sequence point, executes ThisThread::sleepFor() and marks second sequence point.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 */

void function(SequenceAsserter& sequenceAsserter)
{
	sequenceAsserter.sequencePoint(1);
	ThisThread::sleepFor(sleepForDuration);
	sequenceAsserter.sequencePoint(totalThreads + 1);
}

/**
 * \brief Test thread function
 *
 * This function marks first sequence point, passes function() to callOnce() and marks second sequence point.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance
 * \param [in] onceFlag is a reference to OnceFlag shared object
 */

void thread(SequenceAsserter& sequenceAsserter, const SequencePoints sequencePoints, OnceFlag& onceFlag)
{
	sequenceAsserter.sequencePoint(sequencePoints.first);
	callOnce(onceFlag, function, sequenceAsserter);
	sequenceAsserter.sequencePoint(sequencePoints.second);
}

/**
 * \brief Builder of test threads
 *
 * \param [in] priority is the thread's priority
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance
 * \param [in] onceFlag is a reference to OnceFlag shared object
 *
 * \return constructed DynamicThread object
 */

DynamicThread makeTestThread(const uint8_t priority, SequenceAsserter& sequenceAsserter,
		const SequencePoints sequencePoints, OnceFlag& onceFlag)
{
	return makeDynamicThread({testThreadStackSize, priority}, thread, std::ref(sequenceAsserter), sequencePoints,
			std::ref(onceFlag));
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool CallOnceOperationsTestCase::run_() const
{
	const auto contextSwitchCount = statistics::getContextSwitchCount();

	SequenceAsserter sequenceAsserter;
	OnceFlag onceFlag;

	std::array<DynamicThread, totalThreads> threads
	{{
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{0, 10}, onceFlag),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{2, 11}, onceFlag),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{3, 12}, onceFlag),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{4, 13}, onceFlag),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{5, 14}, onceFlag),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{6, 15}, onceFlag),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{7, 16}, onceFlag),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{8, 17}, onceFlag),
	}};

	for (auto& thread : threads)
		thread.start();

	wasteTime(TickClock::duration{});
	const auto start = TickClock::now();

	ThisThread::setPriority(testCasePriority_ - 2);

	bool invalidState {};
	for (size_t i = 1; i < threads.size(); ++i)
		if (threads[i].getState() != ThreadState::blockedOnMutex)
			invalidState = true;

	for (auto& thread : threads)
		thread.join();

	if (invalidState != false)
		return false;

	if (TickClock::now() - start != sleepForDuration + decltype(sleepForDuration){1})
		return false;

	if (sequenceAsserter.assertSequence(totalThreads * 2 + 2) == false)
		return false;

	constexpr auto totalContextSwitches = 2 * totalThreads + 3;
	if (statistics::getContextSwitchCount() - contextSwitchCount != totalContextSwitches)
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<commit_msg>Improve duration measurement in CallOnceOperationsTestCase<commit_after>/**
 * \file
 * \brief CallOnceOperationsTestCase class implementation
 *
 * \author Copyright (C) 2015-2017 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * 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 "CallOnceOperationsTestCase.hpp"

#include "SequenceAsserter.hpp"
#include "wasteTime.hpp"

#include "distortos/callOnce.hpp"
#include "distortos/DynamicThread.hpp"
#include "distortos/statistics.hpp"
#include "distortos/ThisThread.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// sleepFor() duration used in function() passed to callOnce()
constexpr auto sleepForDuration = TickClock::duration{10};

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {512};

/// number of test threads
constexpr size_t totalThreads {8};

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// pair of sequence points
using SequencePoints = std::pair<unsigned int, unsigned int>;

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Test function passed to callOnce().
 *
 * This function marks first sequence point, executes ThisThread::sleepFor() and marks second sequence point.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 */

void function(SequenceAsserter& sequenceAsserter)
{
	sequenceAsserter.sequencePoint(1);
	ThisThread::sleepFor(sleepForDuration);
	sequenceAsserter.sequencePoint(totalThreads + 1);
}

/**
 * \brief Test thread function
 *
 * This function marks first sequence point, passes function() to callOnce(), saves wake time point and marks second
 * sequence point.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance
 * \param [in] onceFlag is a reference to OnceFlag shared object
 * \param [out] timePoint is a reference to variable into which wake time point will be saved
 */

void thread(SequenceAsserter& sequenceAsserter, const SequencePoints sequencePoints, OnceFlag& onceFlag,
		TickClock::time_point& timePoint)
{
	sequenceAsserter.sequencePoint(sequencePoints.first);
	callOnce(onceFlag, function, sequenceAsserter);
	timePoint = TickClock::now();
	sequenceAsserter.sequencePoint(sequencePoints.second);
}

/**
 * \brief Builder of test threads
 *
 * \param [in] priority is the thread's priority
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoints is a pair of sequence points for this instance
 * \param [in] onceFlag is a reference to OnceFlag shared object
 * \param [in] timePoint is a reference to variable into which wake time point of thread will be saved
 *
 * \return constructed DynamicThread object
 */

DynamicThread makeTestThread(const uint8_t priority, SequenceAsserter& sequenceAsserter,
		const SequencePoints sequencePoints, OnceFlag& onceFlag, TickClock::time_point& timePoint)
{
	return makeDynamicThread({testThreadStackSize, priority}, thread, std::ref(sequenceAsserter), sequencePoints,
			std::ref(onceFlag), std::ref(timePoint));
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool CallOnceOperationsTestCase::run_() const
{
	const auto contextSwitchCount = statistics::getContextSwitchCount();

	SequenceAsserter sequenceAsserter;
	OnceFlag onceFlag;
	std::array<TickClock::time_point, totalThreads> timePoints;

	std::array<DynamicThread, totalThreads> threads
	{{
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{0, 10}, onceFlag, timePoints[0]),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{2, 11}, onceFlag, timePoints[1]),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{3, 12}, onceFlag, timePoints[2]),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{4, 13}, onceFlag, timePoints[3]),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{5, 14}, onceFlag, timePoints[4]),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{6, 15}, onceFlag, timePoints[5]),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{7, 16}, onceFlag, timePoints[6]),
			makeTestThread(testCasePriority_ - 1, sequenceAsserter, SequencePoints{8, 17}, onceFlag, timePoints[7]),
	}};

	for (auto& thread : threads)
		thread.start();

	wasteTime(TickClock::duration{});
	const auto start = TickClock::now();

	ThisThread::setPriority(testCasePriority_ - 2);

	bool invalidState {};
	for (size_t i = 1; i < threads.size(); ++i)
		if (threads[i].getState() != ThreadState::blockedOnMutex)
			invalidState = true;

	for (auto& thread : threads)
		thread.join();

	if (invalidState != false)
		return false;

	for (const auto& timePoint : timePoints)
		if (timePoint - start != sleepForDuration + decltype(sleepForDuration){1})
			return false;

	if (sequenceAsserter.assertSequence(totalThreads * 2 + 2) == false)
		return false;

	constexpr auto totalContextSwitches = 2 * totalThreads + 3;
	if (statistics::getContextSwitchCount() - contextSwitchCount != totalContextSwitches)
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<|endoftext|>


<commit_before>// Copyright 2012 Google Inc.
//
// 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.
//
// Author: oschaaf@gmail.com (Otto van der Schaaf)

#include "ngx_cache.h"
#include "ngx_rewrite_options.h"
#include "ngx_rewrite_driver_factory.h"
#include "net/instaweb/util/public/cache_interface.h"
#include "net/instaweb/util/public/cache_stats.h"
#include "net/instaweb/util/public/file_cache.h"
#include "net/instaweb/util/public/file_system_lock_manager.h"
#include "net/instaweb/util/public/lru_cache.h"
#include "net/instaweb/util/public/message_handler.h"
#include "net/instaweb/util/public/shared_mem_lock_manager.h"
#include "net/instaweb/util/public/thread_system.h"
#include "net/instaweb/util/public/threadsafe_cache.h"

namespace net_instaweb {

const char NgxCache::kFileCache[] = "file_cache";
const char NgxCache::kLruCache[] = "lru_cache";

// TODO(oschaaf): refactor this to share as much as possible
// with apache_cache.cc
// The NgxCache shares a file cache per path, with an optional
// LRU Cache
NgxCache::NgxCache(const StringPiece& path,
                   const NgxRewriteOptions& config,
                   NgxRewriteDriverFactory* factory)
    : path_(path.data(), path.size()),
      factory_(factory),
      lock_manager_(NULL),
      file_cache_(NULL) {
  if (config.use_shared_mem_locking()) {
    shared_mem_lock_manager_.reset(new SharedMemLockManager(
        factory->shared_mem_runtime(), StrCat(path, "/named_locks"),
        factory->scheduler(), factory->hasher(), factory->message_handler()));
    lock_manager_ = shared_mem_lock_manager_.get();
  } else {
    FallBackToFileBasedLocking();
  }

  // TODO(jefftk): see the ngx_rewrite_options.h note on OriginRewriteOptions;
  // this would move to OriginRewriteOptions.
  FileCache::CachePolicy* policy = new FileCache::CachePolicy(
      factory->timer(),
      factory->hasher(),
      config.file_cache_clean_interval_ms(),
      config.file_cache_clean_size_kb() * 1024,
      config.file_cache_clean_inode_limit());
  file_cache_ = new FileCache(
      config.file_cache_path(), factory->file_system(), factory->slow_worker(),
      factory->filename_encoder(), policy, factory->message_handler());
  l2_cache_.reset(new CacheStats(kFileCache, file_cache_, factory->timer(),
                                 factory->statistics()));

  if (config.lru_cache_kb_per_process() != 0) {
    LRUCache* lru_cache = new LRUCache(
        config.lru_cache_kb_per_process() * 1024);

    // We only add the threadsafe-wrapper to the LRUCache.  The FileCache
    // is naturally thread-safe because it's got no writable member variables.
    // And surrounding that slower-running class with a mutex would likely
    // cause contention.
    ThreadsafeCache* ts_cache =
        new ThreadsafeCache(lru_cache, factory->thread_system()->NewMutex());
    // TODO(oschaaf): Non-portable (though most major compilers accept it).
#if CACHE_STATISTICS
    l1_cache_.reset(new CacheStats(kLruCache, ts_cache, factory->timer(),
                                   factory->statistics()));
#else
    l1_cache_.reset(ts_cache);
#endif
  }
}

NgxCache::~NgxCache() {
}

// TODO(oschaaf): see rootinit/childinit from ApacheCache.cc

void NgxCache::FallBackToFileBasedLocking() {
  if ((shared_mem_lock_manager_.get() != NULL) || (lock_manager_ == NULL)) {
    shared_mem_lock_manager_.reset(NULL);
    file_system_lock_manager_.reset(new FileSystemLockManager(
        factory_->file_system(), path_,
        factory_->scheduler(), factory_->message_handler()));
    lock_manager_ = file_system_lock_manager_.get();
  }
}

}  // namespace net_instaweb
<commit_msg>Revert "filecache-worker: hook the worker up to the filecache"<commit_after>// Copyright 2012 Google Inc.
//
// 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.
//
// Author: oschaaf@gmail.com (Otto van der Schaaf)

#include "ngx_cache.h"
#include "ngx_rewrite_options.h"
#include "ngx_rewrite_driver_factory.h"
#include "net/instaweb/util/public/cache_interface.h"
#include "net/instaweb/util/public/cache_stats.h"
#include "net/instaweb/util/public/file_cache.h"
#include "net/instaweb/util/public/file_system_lock_manager.h"
#include "net/instaweb/util/public/lru_cache.h"
#include "net/instaweb/util/public/message_handler.h"
#include "net/instaweb/util/public/shared_mem_lock_manager.h"
#include "net/instaweb/util/public/thread_system.h"
#include "net/instaweb/util/public/threadsafe_cache.h"

namespace net_instaweb {

const char NgxCache::kFileCache[] = "file_cache";
const char NgxCache::kLruCache[] = "lru_cache";

// TODO(oschaaf): refactor this to share as much as possible
// with apache_cache.cc
// The NgxCache shares a file cache per path, with an optional
// LRU Cache
NgxCache::NgxCache(const StringPiece& path,
                   const NgxRewriteOptions& config,
                   NgxRewriteDriverFactory* factory)
    : path_(path.data(), path.size()),
      factory_(factory),
      lock_manager_(NULL),
      file_cache_(NULL) {
  if (config.use_shared_mem_locking()) {
    shared_mem_lock_manager_.reset(new SharedMemLockManager(
        factory->shared_mem_runtime(), StrCat(path, "/named_locks"),
        factory->scheduler(), factory->hasher(), factory->message_handler()));
    lock_manager_ = shared_mem_lock_manager_.get();
  } else {
    FallBackToFileBasedLocking();
  }

  // TODO(jefftk): see the ngx_rewrite_options.h note on OriginRewriteOptions;
  // this would move to OriginRewriteOptions.
  FileCache::CachePolicy* policy = new FileCache::CachePolicy(
      factory->timer(),
      factory->hasher(),
      config.file_cache_clean_interval_ms(),
      config.file_cache_clean_size_kb() * 1024,
      config.file_cache_clean_inode_limit());
  file_cache_ = new FileCache(
      config.file_cache_path(), factory->file_system(), NULL,
      factory->filename_encoder(), policy, factory->message_handler());
  l2_cache_.reset(new CacheStats(kFileCache, file_cache_, factory->timer(),
                                 factory->statistics()));

  if (config.lru_cache_kb_per_process() != 0) {
    LRUCache* lru_cache = new LRUCache(
        config.lru_cache_kb_per_process() * 1024);

    // We only add the threadsafe-wrapper to the LRUCache.  The FileCache
    // is naturally thread-safe because it's got no writable member variables.
    // And surrounding that slower-running class with a mutex would likely
    // cause contention.
    ThreadsafeCache* ts_cache =
        new ThreadsafeCache(lru_cache, factory->thread_system()->NewMutex());
    // TODO(oschaaf): Non-portable (though most major compilers accept it).
#if CACHE_STATISTICS
    l1_cache_.reset(new CacheStats(kLruCache, ts_cache, factory->timer(),
                                   factory->statistics()));
#else
    l1_cache_.reset(ts_cache);
#endif
  }
}

NgxCache::~NgxCache() {
}

// TODO(oschaaf): see rootinit/childinit from ApacheCache.cc

void NgxCache::FallBackToFileBasedLocking() {
  if ((shared_mem_lock_manager_.get() != NULL) || (lock_manager_ == NULL)) {
    shared_mem_lock_manager_.reset(NULL);
    file_system_lock_manager_.reset(new FileSystemLockManager(
        factory_->file_system(), path_,
        factory_->scheduler(), factory_->message_handler()));
    lock_manager_ = file_system_lock_manager_.get();
  }
}

}  // namespace net_instaweb
<|endoftext|>