<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 *  $Id$
 */

#if !defined(XMLRECOGNIZER_HPP)
#define XMLRECOGNIZER_HPP

#include <xercesc/util/XercesDefs.hpp>

XERCES_CPP_NAMESPACE_BEGIN

/**
 *  This class provides some simple code to recognize the encodings of
 *  XML files. This recognition only does very basic sensing of the encoding
 *  in a broad sense. Basically its just enough to let us get started and
 *  read the XMLDecl line. The scanner, once it reads the XMLDecl, will
 *  tell the reader any actual encoding string it found and the reader can
 *  update itself to be more specific at that point.
 */
class XMLPARSER_EXPORT XMLRecognizer
{
public :
    // -----------------------------------------------------------------------
    //  Class types
    //
    //  This enum represents the various encoding families that we have to
    //  deal with individually at the scanner level. This does not indicate
    //  the exact encoding, just the rough family that would let us scan
    //  the XML/TextDecl to find the encoding string.
    //
    //  The 'L's and 'B's stand for little or big endian. We conditionally
    //  create versions that will automatically map to the local UTF-16 and
    //  UCS-4 endian modes.
    //
    //  OtherEncoding means that its some transcoder based encoding, i.e. not
    //  one of the ones that we do internally. Its a special case and should
    //  never be used directly outside of the reader.
    //
    //  NOTE: Keep this in sync with the name map array in the Cpp file!!
    // -----------------------------------------------------------------------
    enum Encodings
    {
        EBCDIC          = 0
        , UCS_4B        = 1
        , UCS_4L        = 2
        , US_ASCII      = 3
        , UTF_8         = 4
        , UTF_16B       = 5
        , UTF_16L       = 6

        , Encodings_Count
        , Encodings_Min = EBCDIC
        , Encodings_Max = UTF_16L

        , OtherEncoding = 999

        #if defined(ENDIANMODE_BIG)
        , Def_UTF16     = UTF_16B
        , Def_UCS4      = UCS_4B
        #else
        , Def_UTF16     = UTF_16L
        , Def_UCS4      = UCS_4L
        #endif
    };

    // -----------------------------------------------------------------------
    //  Public, const static data
    //
    //  These are the byte sequences for each of the encodings that we can
    //  auto sense, and their lengths.
    // -----------------------------------------------------------------------
    static const char           fgASCIIPre[];
    static const unsigned int   fgASCIIPreLen;
    static const XMLByte        fgEBCDICPre[];
    static const unsigned int   fgEBCDICPreLen;
    static const XMLByte        fgUTF16BPre[];
    static const XMLByte        fgUTF16LPre[];
    static const unsigned int   fgUTF16PreLen;
    static const XMLByte        fgUCS4BPre[];
    static const XMLByte        fgUCS4LPre[];
    static const unsigned int   fgUCS4PreLen;
    static const char           fgUTF8BOM[];
    static const unsigned int   fgUTF8BOMLen;

    // -----------------------------------------------------------------------
    //  Encoding recognition methods
    // -----------------------------------------------------------------------
    static Encodings basicEncodingProbe
    (
        const   XMLByte* const      rawBuffer
        , const unsigned int        rawByteCount
    );

    static Encodings encodingForName
    (
        const   XMLCh* const    theEncName
    );

    static const XMLCh* nameForEncoding(const Encodings theEncoding);

protected :
    // -----------------------------------------------------------------------
    //  Unimplemented constructors, operators, and destructor
    //
    //  This class is effectively being used as a namespace for some static
    //  methods.
    //
    //   (these functions are protected rather than private only to get rid of
    //    some annoying compiler warnings.)
    //
    // -----------------------------------------------------------------------
    XMLRecognizer();
    ~XMLRecognizer();
    void operator=(const XMLRecognizer&);
};

XERCES_CPP_NAMESPACE_END

#endif
<commit_msg>Performance: XERCES_XMLCH should not be classified as XMLRecognizer::OtherEncodings<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 *  $Id$
 */

#if !defined(XMLRECOGNIZER_HPP)
#define XMLRECOGNIZER_HPP

#include <xercesc/util/XercesDefs.hpp>

XERCES_CPP_NAMESPACE_BEGIN

/**
 *  This class provides some simple code to recognize the encodings of
 *  XML files. This recognition only does very basic sensing of the encoding
 *  in a broad sense. Basically its just enough to let us get started and
 *  read the XMLDecl line. The scanner, once it reads the XMLDecl, will
 *  tell the reader any actual encoding string it found and the reader can
 *  update itself to be more specific at that point.
 */
class XMLPARSER_EXPORT XMLRecognizer
{
public :
    // -----------------------------------------------------------------------
    //  Class types
    //
    //  This enum represents the various encoding families that we have to
    //  deal with individually at the scanner level. This does not indicate
    //  the exact encoding, just the rough family that would let us scan
    //  the XML/TextDecl to find the encoding string.
    //
    //  The 'L's and 'B's stand for little or big endian. We conditionally
    //  create versions that will automatically map to the local UTF-16 and
    //  UCS-4 endian modes.
    //
    //  OtherEncoding means that its some transcoder based encoding, i.e. not
    //  one of the ones that we do internally. Its a special case and should
    //  never be used directly outside of the reader.
    //
    //  NOTE: Keep this in sync with the name map array in the Cpp file!!
    // -----------------------------------------------------------------------
    enum Encodings
    {
        EBCDIC          = 0
        , UCS_4B        = 1
        , UCS_4L        = 2
        , US_ASCII      = 3
        , UTF_8         = 4
        , UTF_16B       = 5
        , UTF_16L       = 6
        , XERCES_XMLCH  = 7

        , Encodings_Count
        , Encodings_Min = EBCDIC
        , Encodings_Max = XERCES_XMLCH

        , OtherEncoding = 999

        #if defined(ENDIANMODE_BIG)
        , Def_UTF16     = UTF_16B
        , Def_UCS4      = UCS_4B
        #else
        , Def_UTF16     = UTF_16L
        , Def_UCS4      = UCS_4L
        #endif
    };

    // -----------------------------------------------------------------------
    //  Public, const static data
    //
    //  These are the byte sequences for each of the encodings that we can
    //  auto sense, and their lengths.
    // -----------------------------------------------------------------------
    static const char           fgASCIIPre[];
    static const unsigned int   fgASCIIPreLen;
    static const XMLByte        fgEBCDICPre[];
    static const unsigned int   fgEBCDICPreLen;
    static const XMLByte        fgUTF16BPre[];
    static const XMLByte        fgUTF16LPre[];
    static const unsigned int   fgUTF16PreLen;
    static const XMLByte        fgUCS4BPre[];
    static const XMLByte        fgUCS4LPre[];
    static const unsigned int   fgUCS4PreLen;
    static const char           fgUTF8BOM[];
    static const unsigned int   fgUTF8BOMLen;

    // -----------------------------------------------------------------------
    //  Encoding recognition methods
    // -----------------------------------------------------------------------
    static Encodings basicEncodingProbe
    (
        const   XMLByte* const      rawBuffer
        , const unsigned int        rawByteCount
    );

    static Encodings encodingForName
    (
        const   XMLCh* const    theEncName
    );

    static const XMLCh* nameForEncoding(const Encodings theEncoding);

protected :
    // -----------------------------------------------------------------------
    //  Unimplemented constructors, operators, and destructor
    //
    //  This class is effectively being used as a namespace for some static
    //  methods.
    //
    //   (these functions are protected rather than private only to get rid of
    //    some annoying compiler warnings.)
    //
    // -----------------------------------------------------------------------
    XMLRecognizer();
    ~XMLRecognizer();
    void operator=(const XMLRecognizer&);
};

XERCES_CPP_NAMESPACE_END

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "core/dom/Document.h"
#include "core/testing/DummyPageHolder.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>

using namespace blink;

namespace {

class MockActiveDOMObject : public ActiveDOMObject {
public:
    MockActiveDOMObject(ExecutionContext* context) : ActiveDOMObject(context) { }

    MOCK_METHOD0(suspend, void());
    MOCK_METHOD0(resume, void());
    MOCK_METHOD0(stop, void());
};

class ActiveDOMObjectTest : public ::testing::Test {
protected:
    ActiveDOMObjectTest();

    Document& srcDocument() const { return m_srcPageHolder->document(); }
    Document& destDocument() const { return m_destPageHolder->document(); }
    MockActiveDOMObject& activeDOMObject() { return m_activeDOMObject; }

private:
    OwnPtr<DummyPageHolder> m_srcPageHolder;
    OwnPtr<DummyPageHolder> m_destPageHolder;
    MockActiveDOMObject m_activeDOMObject;
};

ActiveDOMObjectTest::ActiveDOMObjectTest()
    : m_srcPageHolder(DummyPageHolder::create(IntSize(800, 600)))
    , m_destPageHolder(DummyPageHolder::create(IntSize(800, 600)))
    , m_activeDOMObject(&m_srcPageHolder->document())
{
    m_activeDOMObject.suspendIfNeeded();
}

TEST_F(ActiveDOMObjectTest, NewContextObserved)
{
    unsigned initialSrcCount = srcDocument().activeDOMObjectCount();
    unsigned initialDestCount = destDocument().activeDOMObjectCount();

    EXPECT_CALL(activeDOMObject(), resume());
    activeDOMObject().didMoveToNewExecutionContext(&destDocument());

    EXPECT_EQ(initialSrcCount - 1, srcDocument().activeDOMObjectCount());
    EXPECT_EQ(initialDestCount + 1, destDocument().activeDOMObjectCount());
}

TEST_F(ActiveDOMObjectTest, MoveToActiveDocument)
{
    EXPECT_CALL(activeDOMObject(), resume());
    activeDOMObject().didMoveToNewExecutionContext(&destDocument());
}

TEST_F(ActiveDOMObjectTest, MoveToSuspendedDocument)
{
    destDocument().suspendScheduledTasks();

    EXPECT_CALL(activeDOMObject(), suspend());
    activeDOMObject().didMoveToNewExecutionContext(&destDocument());
}

TEST_F(ActiveDOMObjectTest, MoveToStoppedDocument)
{
    destDocument().detach();

    EXPECT_CALL(activeDOMObject(), stop());
    activeDOMObject().didMoveToNewExecutionContext(&destDocument());
}

} // unnamed namespace
<commit_msg>Oilpan: Move MockActiveDOMObject to Oilpan's heap<commit_after>/*
 * Copyright (c) 2014, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "core/dom/Document.h"
#include "core/testing/DummyPageHolder.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>

using namespace blink;

namespace {

class MockActiveDOMObject final : public GarbageCollectedFinalized<MockActiveDOMObject>, public ActiveDOMObject {
public:
    explicit MockActiveDOMObject(ExecutionContext* context) : ActiveDOMObject(context) { }

    void trace(Visitor*) { }

    MOCK_METHOD0(suspend, void());
    MOCK_METHOD0(resume, void());
    MOCK_METHOD0(stop, void());
};

class ActiveDOMObjectTest : public ::testing::Test {
protected:
    ActiveDOMObjectTest();

    Document& srcDocument() const { return m_srcPageHolder->document(); }
    Document& destDocument() const { return m_destPageHolder->document(); }
    MockActiveDOMObject& activeDOMObject() { return *m_activeDOMObject; }

private:
    OwnPtr<DummyPageHolder> m_srcPageHolder;
    OwnPtr<DummyPageHolder> m_destPageHolder;
    Persistent<MockActiveDOMObject> m_activeDOMObject;
};

ActiveDOMObjectTest::ActiveDOMObjectTest()
    : m_srcPageHolder(DummyPageHolder::create(IntSize(800, 600)))
    , m_destPageHolder(DummyPageHolder::create(IntSize(800, 600)))
    , m_activeDOMObject(new MockActiveDOMObject(&m_srcPageHolder->document()))
{
    m_activeDOMObject->suspendIfNeeded();
}

TEST_F(ActiveDOMObjectTest, NewContextObserved)
{
    unsigned initialSrcCount = srcDocument().activeDOMObjectCount();
    unsigned initialDestCount = destDocument().activeDOMObjectCount();

    EXPECT_CALL(activeDOMObject(), resume());
    activeDOMObject().didMoveToNewExecutionContext(&destDocument());

    EXPECT_EQ(initialSrcCount - 1, srcDocument().activeDOMObjectCount());
    EXPECT_EQ(initialDestCount + 1, destDocument().activeDOMObjectCount());
}

TEST_F(ActiveDOMObjectTest, MoveToActiveDocument)
{
    EXPECT_CALL(activeDOMObject(), resume());
    activeDOMObject().didMoveToNewExecutionContext(&destDocument());
}

TEST_F(ActiveDOMObjectTest, MoveToSuspendedDocument)
{
    destDocument().suspendScheduledTasks();

    EXPECT_CALL(activeDOMObject(), suspend());
    activeDOMObject().didMoveToNewExecutionContext(&destDocument());
}

TEST_F(ActiveDOMObjectTest, MoveToStoppedDocument)
{
    destDocument().detach();

    EXPECT_CALL(activeDOMObject(), stop());
    activeDOMObject().didMoveToNewExecutionContext(&destDocument());
}

} // unnamed namespace
<|endoftext|>


<commit_before>#include "SkBenchmark.h"
#include "SkMatrix.h"
#include "SkRandom.h"
#include "SkString.h"

class MathBench : public SkBenchmark {
    enum {
        kBuffer = 100,
        kLoop   = 10000
    };
    SkString    fName;
    float       fSrc[kBuffer], fDst[kBuffer];
public:
    MathBench(void* param, const char name[]) : INHERITED(param) {
        fName.printf("math_%s", name);

        SkRandom rand;
        for (int i = 0; i < kBuffer; ++i) {
            fSrc[i] = rand.nextSScalar1();
        }
    }

    virtual void performTest(float dst[], const float src[], int count) = 0;

protected:
    virtual int mulLoopCount() const { return 1; }

    virtual const char* onGetName() {
        return fName.c_str();
    }

    virtual void onDraw(SkCanvas* canvas) {
        int n = kLoop * this->mulLoopCount();
        for (int i = 0; i < n; i++) {
            this->performTest(fDst, fSrc, kBuffer);
        }
    }

private:
    typedef SkBenchmark INHERITED;
};

int gMathBench_NonStaticGlobal;

#define always_do(pred)                     \
    do {                                    \
        if (pred) {                         \
            ++gMathBench_NonStaticGlobal; \
        }                                   \
    } while (0)

class NoOpMathBench : public MathBench {
public:
    NoOpMathBench(void* param) : INHERITED(param, "slowIsqrt") {}
protected:
    virtual void performTest(float dst[], const float src[], int count) {
        for (int i = 0; i < count; ++i) {
            dst[i] = src[i] + 1;
        }
    }
private:
    typedef MathBench INHERITED;
};

class SlowISqrtMathBench : public MathBench {
public:
    SlowISqrtMathBench(void* param) : INHERITED(param, "slowIsqrt") {}
protected:
    virtual void performTest(float dst[], const float src[], int count) {
        for (int i = 0; i < count; ++i) {
            dst[i] = 1.0f / sk_float_sqrt(src[i]);
        }
    }
private:
    typedef MathBench INHERITED;
};

static inline float SkFastInvSqrt(float x) {
    float xhalf = 0.5f*x;
    int i = *(int*)&x;
    i = 0x5f3759df - (i>>1);
    x = *(float*)&i;
    x = x*(1.5f-xhalf*x*x);
//    x = x*(1.5f-xhalf*x*x); // this line takes err from 10^-3 to 10^-6
    return x;
}

class FastISqrtMathBench : public MathBench {
public:
    FastISqrtMathBench(void* param) : INHERITED(param, "fastIsqrt") {}
protected:
    virtual void performTest(float dst[], const float src[], int count) {
        for (int i = 0; i < count; ++i) {
            dst[i] = SkFastInvSqrt(src[i]);
        }
    }
private:
    typedef MathBench INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

static SkBenchmark* M0(void* p) { return new NoOpMathBench(p); }
static SkBenchmark* M1(void* p) { return new SlowISqrtMathBench(p); }
static SkBenchmark* M2(void* p) { return new FastISqrtMathBench(p); }

static BenchRegistry gReg0(M0);
static BenchRegistry gReg1(M1);
static BenchRegistry gReg2(M2);
<commit_msg>Change no-op math bench to noOp. http://codereview.appspot.com/4962047/<commit_after>#include "SkBenchmark.h"
#include "SkMatrix.h"
#include "SkRandom.h"
#include "SkString.h"

class MathBench : public SkBenchmark {
    enum {
        kBuffer = 100,
        kLoop   = 10000
    };
    SkString    fName;
    float       fSrc[kBuffer], fDst[kBuffer];
public:
    MathBench(void* param, const char name[]) : INHERITED(param) {
        fName.printf("math_%s", name);

        SkRandom rand;
        for (int i = 0; i < kBuffer; ++i) {
            fSrc[i] = rand.nextSScalar1();
        }
    }

    virtual void performTest(float dst[], const float src[], int count) = 0;

protected:
    virtual int mulLoopCount() const { return 1; }

    virtual const char* onGetName() {
        return fName.c_str();
    }

    virtual void onDraw(SkCanvas* canvas) {
        int n = kLoop * this->mulLoopCount();
        for (int i = 0; i < n; i++) {
            this->performTest(fDst, fSrc, kBuffer);
        }
    }

private:
    typedef SkBenchmark INHERITED;
};

int gMathBench_NonStaticGlobal;

#define always_do(pred)                     \
    do {                                    \
        if (pred) {                         \
            ++gMathBench_NonStaticGlobal; \
        }                                   \
    } while (0)

class NoOpMathBench : public MathBench {
public:
    NoOpMathBench(void* param) : INHERITED(param, "noOp") {}
protected:
    virtual void performTest(float dst[], const float src[], int count) {
        for (int i = 0; i < count; ++i) {
            dst[i] = src[i] + 1;
        }
    }
private:
    typedef MathBench INHERITED;
};

class SlowISqrtMathBench : public MathBench {
public:
    SlowISqrtMathBench(void* param) : INHERITED(param, "slowIsqrt") {}
protected:
    virtual void performTest(float dst[], const float src[], int count) {
        for (int i = 0; i < count; ++i) {
            dst[i] = 1.0f / sk_float_sqrt(src[i]);
        }
    }
private:
    typedef MathBench INHERITED;
};

static inline float SkFastInvSqrt(float x) {
    float xhalf = 0.5f*x;
    int i = *(int*)&x;
    i = 0x5f3759df - (i>>1);
    x = *(float*)&i;
    x = x*(1.5f-xhalf*x*x);
//    x = x*(1.5f-xhalf*x*x); // this line takes err from 10^-3 to 10^-6
    return x;
}

class FastISqrtMathBench : public MathBench {
public:
    FastISqrtMathBench(void* param) : INHERITED(param, "fastIsqrt") {}
protected:
    virtual void performTest(float dst[], const float src[], int count) {
        for (int i = 0; i < count; ++i) {
            dst[i] = SkFastInvSqrt(src[i]);
        }
    }
private:
    typedef MathBench INHERITED;
};

///////////////////////////////////////////////////////////////////////////////

static SkBenchmark* M0(void* p) { return new NoOpMathBench(p); }
static SkBenchmark* M1(void* p) { return new SlowISqrtMathBench(p); }
static SkBenchmark* M2(void* p) { return new FastISqrtMathBench(p); }

static BenchRegistry gReg0(M0);
static BenchRegistry gReg1(M1);
static BenchRegistry gReg2(M2);
<|endoftext|>


<commit_before>#pragma once
#ifndef DELEGATE_HPP
# define DELEGATE_HPP

#include <cassert>

#include <memory>

#include <new>

#include <type_traits>

#include <utility>

template <typename T> class delegate;

template<class R, class ...A>
class delegate<R (A...)>
{
  template <typename U, typename = void> struct is_functora
    : std::false_type { };

  template <typename U>
  struct is_functora<U,
    typename std::enable_if<bool(sizeof((R (U::*)(A...))
      &U::operator()))>::type
  > : std::true_type { };

  template <typename U, typename = void> struct is_functorb
    : std::false_type { };

  template <typename U>
  struct is_functorb<U,
    typename std::enable_if<bool(sizeof((R (U::*)(A...) const)
      &U::operator()))>::type
  > : std::true_type { };

  template <typename U>
  struct is_functor
  {
    static constexpr bool const value = is_functora<U>::value
      || is_functorb<U>::value;
  };

  typedef R (*stub_ptr_type)(void*, A&&...);

  constexpr delegate(void* const o, stub_ptr_type const m)
    : object_ptr_(o),
      stub_ptr_(m)
  {
  }

public:
  constexpr delegate() = default;

  constexpr delegate(delegate const&) = default;

  constexpr delegate(delegate&&) = default;

  template <class C>
  constexpr delegate(C const* const o)
    : object_ptr_(const_cast<C*>(o))
  {
  }

  template <class C>
  constexpr delegate(C const& o)
    : object_ptr_(const_cast<C*>(&o))
  {
  }

  delegate(R (*const function_ptr)(A...))
  {
    *this = from(function_ptr);
  }

  template <class C>
  delegate(C* const object_ptr, R (C::* const method_ptr)(A...))
  {
    *this = from(object_ptr, method_ptr);
  }

  template <class C>
  delegate(C* const object_ptr, R (C::* const method_ptr)(A...) const)
  {
    *this = from(object_ptr, method_ptr);
  }

  template <class C>
  delegate(C& object, R (C::* const method_ptr)(A...))
  {
    *this = from(object, method_ptr);
  }

  template <class C>
  delegate(C const& object, R (C::* const method_ptr)(A...) const)
  {
    *this = from(object, method_ptr);
  }

  template <
    typename T,
    typename = typename std::enable_if<
      !std::is_same<delegate, typename std::remove_const<
        typename std::remove_reference<T>::type>::type>::value
      && is_functor<typename std::remove_reference<T>::type>::value
    >::type
  >
  delegate(T&& f)
    : store_(operator new(sizeof(T)),
        functor_deleter<typename std::remove_reference<T>::type>),
      store_size_(sizeof(T))
  {
    typedef typename std::remove_reference<T>::type functor_type;

    new (store_.get()) functor_type(std::forward<T>(f));

    object_ptr_ = store_.get();

    stub_ptr_ = functor_stub<functor_type>;

    deleter_ = destructor_stub<functor_type>;
  }

  delegate& operator=(delegate const&) = default;

  delegate& operator=(delegate&& rhs) = default;

  template <class C>
  delegate& operator=(R (C::* const rhs)(A...))
  {
    return *this = from(static_cast<C*>(object_ptr_), rhs);
  }

  template <class C>
  delegate& operator=(R (C::* const rhs)(A...) const)
  {
    return *this = from(static_cast<C const*>(object_ptr_), rhs);
  }

  template <
    typename T,
    typename = typename std::enable_if<
      !std::is_same<delegate, typename std::remove_const<
        typename std::remove_reference<T>::type>::type>::value
      && is_functor<typename std::remove_reference<T>::type>::value
    >::type
  >
  delegate& operator=(T&& f)
  {
    typedef typename std::remove_reference<T>::type functor_type;

    if ((sizeof(T) > store_size_)
      || (decltype(store_.use_count())(1) != store_.use_count()))
    {
      store_.reset(operator new(sizeof(T)), functor_deleter<functor_type>);

      store_size_ = sizeof(T);
    }
    else
    {
      deleter_(store_.get());
    }

    new (store_.get()) functor_type(std::forward<T>(f));

    object_ptr_ = store_.get();

    stub_ptr_ = functor_stub<functor_type>;

    deleter_ = destructor_stub<functor_type>;

    return *this;
  }

  template <R (* const function_ptr)(A...)>
  static constexpr delegate from()
  {
    return { nullptr, function_stub<function_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...)>
  static constexpr delegate from(C* object_ptr)
  {
    return { object_ptr, method_stub<C, method_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...) const>
  static constexpr delegate from(C const* object_ptr)
  {
    return { const_cast<C*>(object_ptr),
      const_method_stub<C, method_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...)>
  static constexpr delegate from(C& object)
  {
    return { &object, method_stub<C, method_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...) const>
  static constexpr delegate from(C const& object)
  {
    return { const_cast<C*>(&object),
      const_method_stub<C, method_ptr> };
  }

  template <typename T>
  static delegate from(T&& f)
  {
    return { std::forward<T>(f) };
  }

  static constexpr delegate from(R (* const function_ptr)(A...))
  {
    return { [function_ptr](A&&... args){
      return (*function_ptr)(std::forward<A>(args)...); } };
  }

  template <class C>
  static constexpr delegate from(C* const object_ptr,
    R (C::* const method_ptr)(A...))
  {
    return { [object_ptr, method_ptr](A&&... args){
      return (object_ptr->*method_ptr)(std::forward<A>(args)...); } };
  }

  template <class C>
  static constexpr delegate from(C const* const object_ptr,
    R (C::* const method_ptr)(A...) const)
  {
    return { [object_ptr, method_ptr](A&&... args){
      return (object_ptr->*method_ptr)(std::forward<A>(args)...); } };
  }

  template <class C>
  static constexpr delegate from(C& object,
   R (C::* const method_ptr)(A...))
  {
    return { [&object, method_ptr](A&&... args){
      return (object.*method_ptr)(std::forward<A>(args)...); } };
  }

  template <class C>
  static constexpr delegate from(C const& object,
    R (C::* const method_ptr)(A...) const)
  {
    return { [&object, method_ptr](A&&... args){
      return (object.*method_ptr)(std::forward<A>(args)...); } };
  }

  void reset() { stub_ptr_ = nullptr; store_.reset(); }

  void swap(delegate& other) { ::std::swap(*this, other); }

  constexpr bool operator==(delegate const& rhs) const
  {
    return (object_ptr_ == rhs.object_ptr_) && (stub_ptr_ == rhs.stub_ptr_);
  }

  constexpr bool operator!=(delegate const& rhs) const
  {
    return !operator==(rhs);
  }

  constexpr bool operator<(delegate const& rhs) const
  {
    return (object_ptr_ < rhs.object_ptr_) || (stub_ptr_ < rhs.stub_ptr_);
  }

  constexpr explicit operator bool() const { return stub_ptr_; }

  constexpr R operator()(A... args) const
  {
//  assert(stub_ptr);
    return stub_ptr_(object_ptr_, std::forward<A>(args)...);
  }

private:
  friend class ::std::hash<delegate>;

  typedef void (*deleter_type)(void*);

  void* object_ptr_{};
  stub_ptr_type stub_ptr_{};

  deleter_type deleter_;

  std::shared_ptr<void> store_;
  std::size_t store_size_;

  template <class T>
  static void destructor_stub(void* const p)
  {
    static_cast<T*>(p)->~T();
  }

  template <class T>
  static void functor_deleter(void* const p)
  {
    static_cast<T*>(p)->~T();

    operator delete(p);
  }

  template <R (*function_ptr)(A...)>
  static constexpr R function_stub(void* const, A&&... args)
  {
    return function_ptr(std::forward<A>(args)...);
  }

  template <class C, R (C::*method_ptr)(A...)>
  static constexpr R method_stub(void* const object_ptr, A&&... args)
  {
    return (static_cast<C*>(object_ptr)->*method_ptr)(
      std::forward<A>(args)...);
  }

  template <class C, R (C::*method_ptr)(A...) const>
  static constexpr R const_method_stub(void* const object_ptr, A&&... args)
  {
    return (static_cast<C const*>(object_ptr)->*method_ptr)(
      std::forward<A>(args)...);
  }

  template <typename T>
  static constexpr R functor_stub(void* const object_ptr, A&&... args)
  {
    return (*static_cast<T*>(object_ptr))(std::forward<A>(args)...);
  }
};

namespace std
{
  template <typename R, typename ...A>
  struct hash<delegate<R (A...)> >
  {
    size_t operator()(delegate<R (A...)> const& d) const
    {
      auto const seed(hash<void*>()(d.object_ptr_) + 0x9e3779b9);

      return hash<typename delegate<R (A...)>::stub_ptr_type>()(d.stub_ptr_)
        + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    }
  };
}

#endif // DELEGATE_HPP
<commit_msg>strips<commit_after>#pragma once
#ifndef DELEGATE_HPP
# define DELEGATE_HPP

#include <cassert>

#include <memory>

#include <new>

#include <type_traits>

#include <utility>

template <typename T> class delegate;

template<class R, class ...A>
class delegate<R (A...)>
{
  template <typename U, typename = void> struct is_functora
    : std::false_type { };

  template <typename U>
  struct is_functora<U,
    typename std::enable_if<bool(sizeof((R (U::*)(A...))
      &U::operator()))>::type
  > : std::true_type { };

  template <typename U, typename = void> struct is_functorb
    : std::false_type { };

  template <typename U>
  struct is_functorb<U,
    typename std::enable_if<bool(sizeof((R (U::*)(A...) const)
      &U::operator()))>::type
  > : std::true_type { };

  template <typename U>
  struct is_functor
  {
    static constexpr bool const value = is_functora<U>::value
      || is_functorb<U>::value;
  };

  typedef R (*stub_ptr_type)(void*, A&&...);

  constexpr delegate(void* const o, stub_ptr_type const m)
    : object_ptr_(o),
      stub_ptr_(m)
  {
  }

public:
  constexpr delegate() = default;

  constexpr delegate(delegate const&) = default;

  constexpr delegate(delegate&&) = default;

  template <class C>
  constexpr delegate(C const* const o)
    : object_ptr_(const_cast<C*>(o))
  {
  }

  template <class C>
  constexpr delegate(C const& o)
    : object_ptr_(const_cast<C*>(&o))
  {
  }

  delegate(R (* const function_ptr)(A...))
  {
    *this = from(function_ptr);
  }

  template <class C>
  delegate(C* const object_ptr, R (C::* const method_ptr)(A...))
  {
    *this = from(object_ptr, method_ptr);
  }

  template <class C>
  delegate(C* const object_ptr, R (C::* const method_ptr)(A...) const)
  {
    *this = from(object_ptr, method_ptr);
  }

  template <class C>
  delegate(C& object, R (C::* const method_ptr)(A...))
  {
    *this = from(object, method_ptr);
  }

  template <class C>
  delegate(C const& object, R (C::* const method_ptr)(A...) const)
  {
    *this = from(object, method_ptr);
  }

  template <
    typename T,
    typename = typename std::enable_if<
      !std::is_same<delegate, typename std::remove_const<
        typename std::remove_reference<T>::type>::type>::value
      && is_functor<typename std::remove_reference<T>::type>::value
    >::type
  >
  delegate(T&& f)
    : store_(operator new(sizeof(T)),
        functor_deleter<typename std::remove_reference<T>::type>),
      store_size_(sizeof(T))
  {
    typedef typename std::remove_reference<T>::type functor_type;

    new (store_.get()) functor_type(std::forward<T>(f));

    object_ptr_ = store_.get();

    stub_ptr_ = functor_stub<functor_type>;

    deleter_ = destructor_stub<functor_type>;
  }

  delegate& operator=(delegate const&) = default;

  delegate& operator=(delegate&& rhs) = default;

  template <class C>
  delegate& operator=(R (C::* const rhs)(A...))
  {
    return *this = from(static_cast<C*>(object_ptr_), rhs);
  }

  template <class C>
  delegate& operator=(R (C::* const rhs)(A...) const)
  {
    return *this = from(static_cast<C const*>(object_ptr_), rhs);
  }

  template <
    typename T,
    typename = typename std::enable_if<
      !std::is_same<delegate, typename std::remove_const<
        typename std::remove_reference<T>::type>::type>::value
      && is_functor<typename std::remove_reference<T>::type>::value
    >::type
  >
  delegate& operator=(T&& f)
  {
    typedef typename std::remove_reference<T>::type functor_type;

    if ((sizeof(T) > store_size_)
      || (decltype(store_.use_count())(1) != store_.use_count()))
    {
      store_.reset(operator new(sizeof(T)), functor_deleter<functor_type>);

      store_size_ = sizeof(T);
    }
    else
    {
      deleter_(store_.get());
    }

    new (store_.get()) functor_type(std::forward<T>(f));

    object_ptr_ = store_.get();

    stub_ptr_ = functor_stub<functor_type>;

    deleter_ = destructor_stub<functor_type>;

    return *this;
  }

  template <R (* const function_ptr)(A...)>
  static constexpr delegate from()
  {
    return { nullptr, function_stub<function_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...)>
  static constexpr delegate from(C* object_ptr)
  {
    return { object_ptr, method_stub<C, method_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...) const>
  static constexpr delegate from(C const* object_ptr)
  {
    return { const_cast<C*>(object_ptr), const_method_stub<C, method_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...)>
  static constexpr delegate from(C& object)
  {
    return { &object, method_stub<C, method_ptr> };
  }

  template <class C, R (C::* const method_ptr)(A...) const>
  static constexpr delegate from(C const& object)
  {
    return { const_cast<C*>(&object), const_method_stub<C, method_ptr> };
  }

  template <typename T>
  static constexpr delegate from(T&& f)
  {
    return { std::forward<T>(f) };
  }

  static constexpr delegate from(R (* const function_ptr)(A...))
  {
    return { [function_ptr](A&&... args) {
      return (*function_ptr)(std::forward<A>(args)...); } };
  }

  template <class C>
  static constexpr delegate from(C* const object_ptr,
    R (C::* const method_ptr)(A...))
  {
    return { [object_ptr, method_ptr](A&&... args) {
      return (object_ptr->*method_ptr)(std::forward<A>(args)...); } };
  }

  template <class C>
  static constexpr delegate from(C const* const object_ptr,
    R (C::* const method_ptr)(A...) const)
  {
    return { [object_ptr, method_ptr](A&&... args) {
      return (object_ptr->*method_ptr)(std::forward<A>(args)...); } };
  }

  template <class C>
  static constexpr delegate from(C& object,
   R (C::* const method_ptr)(A...))
  {
    return { [&object, method_ptr](A&&... args) {
      return (object.*method_ptr)(std::forward<A>(args)...); } };
  }

  template <class C>
  static constexpr delegate from(C const& object,
    R (C::* const method_ptr)(A...) const)
  {
    return { [&object, method_ptr](A&&... args) {
      return (object.*method_ptr)(std::forward<A>(args)...); } };
  }

  void reset() { stub_ptr_ = nullptr; store_.reset(); }

  constexpr void swap(delegate& other) { ::std::swap(*this, other); }

  constexpr bool operator==(delegate const& rhs) const
  {
    return (object_ptr_ == rhs.object_ptr_) && (stub_ptr_ == rhs.stub_ptr_);
  }

  constexpr bool operator!=(delegate const& rhs) const
  {
    return !operator==(rhs);
  }

  constexpr bool operator<(delegate const& rhs) const
  {
    return (object_ptr_ < rhs.object_ptr_) || (stub_ptr_ < rhs.stub_ptr_);
  }

  constexpr explicit operator bool() const { return stub_ptr_; }

  constexpr R operator()(A... args) const
  {
//  assert(stub_ptr);
    return stub_ptr_(object_ptr_, std::forward<A>(args)...);
  }

private:
  friend class ::std::hash<delegate>;

  typedef void (*deleter_type)(void*);

  void* object_ptr_{};
  stub_ptr_type stub_ptr_{};

  deleter_type deleter_;

  std::shared_ptr<void> store_;
  std::size_t store_size_;

  template <class T>
  static constexpr void destructor_stub(void* const p)
  {
    static_cast<T*>(p)->~T();
  }

  template <class T>
  static void functor_deleter(void* const p)
  {
    static_cast<T*>(p)->~T();

    operator delete(p);
  }

  template <R (*function_ptr)(A...)>
  static constexpr R function_stub(void* const, A&&... args)
  {
    return function_ptr(std::forward<A>(args)...);
  }

  template <class C, R (C::*method_ptr)(A...)>
  static constexpr R method_stub(void* const object_ptr, A&&... args)
  {
    return (static_cast<C*>(object_ptr)->*method_ptr)(
      std::forward<A>(args)...);
  }

  template <class C, R (C::*method_ptr)(A...) const>
  static constexpr R const_method_stub(void* const object_ptr, A&&... args)
  {
    return (static_cast<C const*>(object_ptr)->*method_ptr)(
      std::forward<A>(args)...);
  }

  template <typename T>
  static constexpr R functor_stub(void* const object_ptr, A&&... args)
  {
    return (*static_cast<T*>(object_ptr))(std::forward<A>(args)...);
  }
};

namespace std
{
  template <typename R, typename ...A>
  struct hash<delegate<R (A...)> >
  {
    size_t operator()(delegate<R (A...)> const& d) const
    {
      auto const seed(hash<void*>()(d.object_ptr_) + 0x9e3779b9);

      return hash<typename delegate<R (A...)>::stub_ptr_type>()(d.stub_ptr_)
        + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    }
  };
}

#endif // DELEGATE_HPP
<|endoftext|>


<commit_before>#include "messaging.hpp"

typedef struct {
	long address;
	std::string dat;
	long busTime;
	long src;
} can_frame;

extern "C" {

void can_list_to_can_capnp_cpp(const std::vector<can_frame> &can_list, std::string &out, bool sendCan, bool valid) {
  MessageBuilder msg;
  auto event = msg.initEvent(valid);

  auto canData = sendCan ? event.initSendcan(can_list.size()) : event.initCan(can_list.size());
  int j = 0;
  for (auto it = can_list.begin(); it != can_list.end(); it++, j++) {
    auto c = canData[j];
    c.setAddress(it->address);
    c.setBusTime(it->busTime);
    c.setDat(kj::arrayPtr((uint8_t*)it->dat.data(), it->dat.size()));
    c.setSrc(it->src);
  }
  auto bytes = msg.toBytes();
  out.append((const char *)bytes.begin(), bytes.size());
}

}
<commit_msg>can_list_to_can_capnp_cpp: write message directly to the output string (#19912)<commit_after>#include "messaging.hpp"

typedef struct {
	long address;
	std::string dat;
	long busTime;
	long src;
} can_frame;

extern "C" {

void can_list_to_can_capnp_cpp(const std::vector<can_frame> &can_list, std::string &out, bool sendCan, bool valid) {
  MessageBuilder msg;
  auto event = msg.initEvent(valid);

  auto canData = sendCan ? event.initSendcan(can_list.size()) : event.initCan(can_list.size());
  int j = 0;
  for (auto it = can_list.begin(); it != can_list.end(); it++, j++) {
    auto c = canData[j];
    c.setAddress(it->address);
    c.setBusTime(it->busTime);
    c.setDat(kj::arrayPtr((uint8_t*)it->dat.data(), it->dat.size()));
    c.setSrc(it->src);
  }
  const uint64_t msg_size = capnp::computeSerializedSizeInWords(msg) * sizeof(capnp::word);
  out.resize(msg_size);
  kj::ArrayOutputStream output_stream(kj::ArrayPtr<capnp::byte>((unsigned char *)out.data(), msg_size));
  capnp::writeMessage(output_stream, msg);
}

}
<|endoftext|>


<commit_before>/*=============================================================================
  NiftyLink:  A software library to facilitate communication over OpenIGTLink.

  Copyright (c) University College London (UCL). All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  See LICENSE.txt in the top level directory for details.
=============================================================================*/

#include <QObject>
#include <QApplication>
#include <QtGui/QImage>
#include <QUrl>
#include <QTest>
#include <iostream>
#include <igtlTimeStamp.h>
#include "OIGTLSocketObject.h"
#include "OIGTLImageMessage.h"
#include "TestImagingSender.h"

//-----------------------------------------------------------------------------
TestImagingSender::TestImagingSender(const QImage* image,
    const QString& hostName,
    const int& portNumber,
    const int& numberOfIterations
    )
  : m_Image(image)
  , m_HostName(hostName)
  , m_PortNumber(portNumber)
  , m_NumberOfIterations(numberOfIterations)
{
  m_TimePackingMessage = 0;
  m_NumberSent = 0;

  connect(&m_Socket, SIGNAL(messageSent(unsigned long long)), this, SLOT(OnMessageSent(unsigned long long)));
  connect(&m_Socket, SIGNAL(connectedToRemoteSignal()), this, SLOT(OnConnectToRemote()));
  connect(&m_Socket, SIGNAL(lostConnectionToRemoteSignal()), this, SLOT(OnLostConnectionToRemote()));
  connect(&m_Socket, SIGNAL(shutdownSender()), this, SLOT(OnShutdownSender()));
}

//-----------------------------------------------------------------------------
TestImagingSender::~TestImagingSender()
{
}

//-----------------------------------------------------------------------------
void TestImagingSender::OnConnectToRemote()
{
  std::cout << "Connected" << std::endl;
}

//-----------------------------------------------------------------------------
void TestImagingSender::OnLostConnectionToRemote()
{
  std::cerr << "Remote end disconnected" << std::endl;
  emit Done();
}

//-----------------------------------------------------------------------------
void TestImagingSender::FinishUp()
{
  if (m_Socket.isConnected())
  {
    m_Socket.closeSocket();
  }
}

//-----------------------------------------------------------------------------
void TestImagingSender::OnShutdownSender()
{
  std::cerr << "My sender thread shutdown" << std::endl;
  emit Done();
}

//-----------------------------------------------------------------------------
void TestImagingSender::OnMessageSent(unsigned long long timestamp)
{
  m_NumberSent++;
}

//-----------------------------------------------------------------------------
bool TestImagingSender::Setup()
{
  QUrl url;
  url.setHost(m_HostName);
  url.setPort(m_PortNumber);

  bool connectionResult = m_Socket.connectToRemote(url);

  if (!connectionResult)
  {
    std::cerr << "Failed to connect to host=" << m_HostName.toStdString() << ", port=" << m_PortNumber << std::endl;
  }

  return connectionResult;
}

//-----------------------------------------------------------------------------
void TestImagingSender::Run()
{
  if(this->Setup())
  {
    while(!m_Socket.isConnected())
    {
      QTest::qWait(250);
    }

    igtl::TimeStamp::Pointer startTime = igtl::TimeStamp::New();
    startTime->GetTime();

    // Throw data at the socket.
    this->SendData(m_NumberOfIterations);

    while(m_NumberSent < m_NumberOfIterations)
    {
      QTest::qWait(10);
    }

    // Finish
    igtl::TimeStamp::Pointer endTime = igtl::TimeStamp::New();
    endTime->GetTime();

    // Calculate results
    igtlUint64 result = GetDifferenceInNanoSeconds(endTime, startTime);
    double bps = (m_NumberOfIterations*(m_Image->byteCount())*8) / ((double)result/(double)1000000000.0);

    std::cout << "Timing: for " << m_NumberOfIterations << " iterations:" << std::endl;
    std::cout << "  total time=" << result / (double)1000000000.0 << "(s)" << std::endl;
    std::cout << "         fps=" << 1.0/((double)result/(double)m_NumberOfIterations/1000000000.0) << std::endl;
    std::cout << "         bps=" << bps << std::endl;
    std::cout << "        kbps=" << bps/1024 << std::endl;
    std::cout << "        mbps=" << bps/1024/1024 << std::endl;
    std::cout << "     packing=" << m_TimePackingMessage / (double)1000000000.0 << "(s)" << " (" << 100.0*(double)m_TimePackingMessage/(double)result << "%)" << std::endl;

    // Tidy up.
    this->FinishUp();
  }
}

//-----------------------------------------------------------------------------
void TestImagingSender::SendData(const int& numberOfIterations)
{

  for (int i = 0; i < numberOfIterations; i++)
  {
    igtl::TimeStamp::Pointer startIteration = igtl::TimeStamp::New();

    igtl::Matrix4x4 matrix;
    OIGTLImageMessage::Pointer msg = (OIGTLImageMessage::Pointer(new OIGTLImageMessage()));
    msg->setQImage(*m_Image);
    msg->setMatrix(matrix);

    igtl::TimeStamp::Pointer endPacking = igtl::TimeStamp::New();
    endPacking->GetTime();

    m_Socket.sendMessage(msg);

    igtl::TimeStamp::Pointer endSending = igtl::TimeStamp::New();
    endSending->GetTime();

    igtlUint64 nanos = GetDifferenceInNanoSeconds(endPacking, startIteration);
    m_TimePackingMessage += nanos;
  }
}

//-----------------------------------------------------------------------------
int main(int argc, char** argv)
{

  //------------------------------------------------------------
  // Parse Arguments

  if (argc != 5) // check number of arguments
    {
    // If not correct, print usage
    std::cerr << "Usage: " << argv[0] << " <hostname> <port> <iters> <filename>" << std::endl;
    std::cerr << "    <hostname> : IP or host name"                              << std::endl;
    std::cerr << "    <port>     : Port #"                                       << std::endl;
    std::cerr << "    <iters>    : Number of iterations"                         << std::endl;
    std::cerr << "    <filename> : Image file to send (.raw or .png)"            << std::endl;
    exit(0);
    }

  char*  hostname   = argv[1];
  int    port       = atoi(argv[2]);
  int    iters      = atoi(argv[3]);
  char*  imagename  = argv[4];

  std::cout << "TestImagingSender:" << std::endl;
  std::cout << " to host:" << hostname << std::endl;
  std::cout << " on port:" << port << std::endl;
  std::cout << "   iters:" << iters << std::endl;
  std::cout << "     img:" << imagename << std::endl;

  // Load image
  QImage image;
  if (!image.load(imagename))
  {
    std::cerr << "Failed to load image:" << imagename << std::endl;
    return EXIT_FAILURE;
  }

  TestImagingSender sender(&image, QString(hostname), port, iters);

  QApplication app(argc,argv);
  QObject::connect(&sender, SIGNAL(Done()), &app, SLOT(quit()), Qt::QueuedConnection);

  QTimer::singleShot(220, &sender, SLOT(Run()));
  int ret = app.exec();

  return ret;
}
<commit_msg>Bug #1974: Tweaks for network stats in TestImagingSender<commit_after>/*=============================================================================
  NiftyLink:  A software library to facilitate communication over OpenIGTLink.

  Copyright (c) University College London (UCL). All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  See LICENSE.txt in the top level directory for details.
=============================================================================*/

#include <QObject>
#include <QApplication>
#include <QtGui/QImage>
#include <QUrl>
#include <QTest>
#include <iostream>
#include <igtlTimeStamp.h>
#include "OIGTLSocketObject.h"
#include "OIGTLImageMessage.h"
#include "TestImagingSender.h"

//-----------------------------------------------------------------------------
TestImagingSender::TestImagingSender(const QImage* image,
    const QString& hostName,
    const int& portNumber,
    const int& numberOfIterations
    )
  : m_Image(image)
  , m_HostName(hostName)
  , m_PortNumber(portNumber)
  , m_NumberOfIterations(numberOfIterations)
{
  m_TimePackingMessage = 0;
  m_NumberSent = 0;

  connect(&m_Socket, SIGNAL(messageSent(unsigned long long)), this, SLOT(OnMessageSent(unsigned long long)));
  connect(&m_Socket, SIGNAL(connectedToRemoteSignal()), this, SLOT(OnConnectToRemote()));
  connect(&m_Socket, SIGNAL(lostConnectionToRemoteSignal()), this, SLOT(OnLostConnectionToRemote()));
  connect(&m_Socket, SIGNAL(shutdownSender()), this, SLOT(OnShutdownSender()));
}

//-----------------------------------------------------------------------------
TestImagingSender::~TestImagingSender()
{
}

//-----------------------------------------------------------------------------
void TestImagingSender::OnConnectToRemote()
{
  std::cout << "Connected" << std::endl;
}

//-----------------------------------------------------------------------------
void TestImagingSender::OnLostConnectionToRemote()
{
  std::cerr << "Remote end disconnected" << std::endl;
  emit Done();
}

//-----------------------------------------------------------------------------
void TestImagingSender::FinishUp()
{
  if (m_Socket.isConnected())
  {
    m_Socket.closeSocket();
  }
}

//-----------------------------------------------------------------------------
void TestImagingSender::OnShutdownSender()
{
  std::cerr << "My sender thread shutdown" << std::endl;
  emit Done();
}

//-----------------------------------------------------------------------------
void TestImagingSender::OnMessageSent(unsigned long long timestamp)
{
  m_NumberSent++;
}

//-----------------------------------------------------------------------------
bool TestImagingSender::Setup()
{
  QUrl url;
  url.setHost(m_HostName);
  url.setPort(m_PortNumber);

  bool connectionResult = m_Socket.connectToRemote(url);

  if (!connectionResult)
  {
    std::cerr << "Failed to connect to host=" << m_HostName.toStdString() << ", port=" << m_PortNumber << std::endl;
  }

  return connectionResult;
}

//-----------------------------------------------------------------------------
void TestImagingSender::Run()
{
  if(this->Setup())
  {
    while(!m_Socket.isConnected())
    {
      QTest::qWait(250);
    }

    igtl::TimeStamp::Pointer startTime = igtl::TimeStamp::New();
    startTime->GetTime();

    // Throw data at the socket.
    this->SendData(m_NumberOfIterations);

    while(m_NumberSent < m_NumberOfIterations)
    {
      QTest::qWait(10);
    }

    // Finish
    igtl::TimeStamp::Pointer endTime = igtl::TimeStamp::New();
    endTime->GetTime();

    // Calculate results
    igtlUint64 result = GetDifferenceInNanoSeconds(endTime, startTime);
    double bps = ((double)m_NumberOfIterations*((double)m_Image->byteCount())*(double)8) / ((double)result/(double)1000000000.0);

    std::cout << "Timing: for " << m_NumberOfIterations << " iterations:" << std::endl;
    std::cout << "  total time=" << result / (double)1000000000.0 << "(s)" << std::endl;
    std::cout << "         fps=" << 1.0/((double)result/(double)m_NumberOfIterations/1000000000.0) << std::endl;
    std::cout << "         bps=" << bps << std::endl;
    std::cout << "        kbps=" << bps/(double)1024 << std::endl;
    std::cout << "        mbps=" << bps/(double)1024/(double)1024 << std::endl;
    std::cout << "     packing=" << m_TimePackingMessage / (double)1000000000.0 << "(s)" << " (" << 100.0*(double)m_TimePackingMessage/(double)result << "%)" << std::endl;

    // Tidy up.
    this->FinishUp();
  }
}

//-----------------------------------------------------------------------------
void TestImagingSender::SendData(const int& numberOfIterations)
{

  for (int i = 0; i < numberOfIterations; i++)
  {
    igtl::TimeStamp::Pointer startIteration = igtl::TimeStamp::New();

    igtl::Matrix4x4 matrix;
    OIGTLImageMessage::Pointer msg(new OIGTLImageMessage());
    msg->setQImage(*m_Image);
    msg->setMatrix(matrix);

    igtl::TimeStamp::Pointer endPacking = igtl::TimeStamp::New();
    endPacking->GetTime();

    m_Socket.sendMessage(msg);

    igtl::TimeStamp::Pointer endSending = igtl::TimeStamp::New();
    endSending->GetTime();

    igtlUint64 nanos = GetDifferenceInNanoSeconds(endPacking, startIteration);
    m_TimePackingMessage += nanos;
  }
}

//-----------------------------------------------------------------------------
int main(int argc, char** argv)
{

  //------------------------------------------------------------
  // Parse Arguments

  if (argc != 5) // check number of arguments
    {
    // If not correct, print usage
    std::cerr << "Usage: " << argv[0] << " <hostname> <port> <iters> <filename>" << std::endl;
    std::cerr << "    <hostname> : IP or host name"                              << std::endl;
    std::cerr << "    <port>     : Port #"                                       << std::endl;
    std::cerr << "    <iters>    : Number of iterations"                         << std::endl;
    std::cerr << "    <filename> : Image file to send (.raw or .png)"            << std::endl;
    exit(0);
    }

  char*  hostname   = argv[1];
  int    port       = atoi(argv[2]);
  int    iters      = atoi(argv[3]);
  char*  imagename  = argv[4];

  std::cout << "TestImagingSender:" << std::endl;
  std::cout << " to host:" << hostname << std::endl;
  std::cout << " on port:" << port << std::endl;
  std::cout << "   iters:" << iters << std::endl;
  std::cout << "     img:" << imagename << std::endl;

  // Load image
  QImage image;
  if (!image.load(imagename))
  {
    std::cerr << "Failed to load image:" << imagename << std::endl;
    return EXIT_FAILURE;
  }
  image.convertToFormat(QImage::Format_Indexed8);
  TestImagingSender sender(&image, QString(hostname), port, iters);

  QApplication app(argc,argv);
  QObject::connect(&sender, SIGNAL(Done()), &app, SLOT(quit()), Qt::QueuedConnection);

  QTimer::singleShot(220, &sender, SLOT(Run()));
  int ret = app.exec();

  return ret;
}
<|endoftext|>


<commit_before>/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

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

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

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

#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
#pragma implementation
#endif

#include "listener.h"
#include "priv.h"
#include <m_string.h>
#include <mysql.h>
#include <violite.h>
#ifndef __WIN__
#include <sys/un.h>
#endif
#include <sys/stat.h>

#include "thread_registry.h"
#include "options.h"
#include "instance_map.h"
#include "log.h"
#include "mysql_connection.h"
#include "portability.h"

static void set_non_blocking(int socket)
{
#ifndef __WIN__
  int flags= fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags | O_NONBLOCK);
#else
  u_long arg= 1;
  ioctlsocket(socket, FIONBIO, &arg);
#endif
}

static void set_no_inherit(int socket)
{
#ifndef __WIN__
  int flags= fcntl(socket, F_GETFD, 0);
  fcntl(socket, F_SETFD, flags | FD_CLOEXEC);
#endif
}

/*
  Listener_thread - incapsulates listening functionality
*/

class Listener_thread: public Listener_thread_args
{
public:
  Listener_thread(const Listener_thread_args &args);
  ~Listener_thread();
  void run();
private:
  static const int LISTEN_BACK_LOG_SIZE= 5;     /* standard backlog size */
  ulong total_connection_count;
  Thread_info thread_info;

  int     sockets[2];
  int     num_sockets;
  fd_set  read_fds;
private:
  void handle_new_mysql_connection(Vio *vio);
  int   create_tcp_socket();
  int   create_unix_socket(struct sockaddr_un &unix_socket_address);
};

Listener_thread::Listener_thread(const Listener_thread_args &args) :
  Listener_thread_args(args.thread_registry, args.options, args.user_map,
                       args.instance_map)
  ,total_connection_count(0)
  ,thread_info(pthread_self())
  ,num_sockets(0)
{
}

Listener_thread::~Listener_thread()
{
}

/*
  Listener_thread::run() - listen all supported sockets and spawn a thread
  to handle incoming connection.
  Using 'die' in case of syscall failure is OK now - we don't hold any
  resources and 'die' kills the signal thread automatically. To be rewritten
  one day.
  See also comments in mysqlmanager.cc to picture general Instance Manager
  architecture.
*/

void Listener_thread::run()
{
  int i, n= 0;

#ifndef __WIN__
  /* we use this var to check whether we are running on LinuxThreads */
  pid_t thread_pid;

  thread_pid= getpid();

  struct sockaddr_un unix_socket_address;
  /* set global variable */
  linuxthreads= (thread_pid != manager_pid);
#endif

  thread_registry.register_thread(&thread_info);

  my_thread_init();

  FD_ZERO(&read_fds);

  /* I. prepare 'listen' sockets */
  if (create_tcp_socket())
    goto err;

#ifndef __WIN__
  if (create_unix_socket(unix_socket_address))
    goto err;
#endif

  /* II. Listen sockets and spawn childs */
  for (i= 0; i < num_sockets; i++)
    n= max(n, sockets[i]);
  n++;

  timeval tv;
  while (!thread_registry.is_shutdown())
  {
    fd_set read_fds_arg= read_fds;
    /*
      We should reintialize timer as on linux it is modified
      to reflect amount of time not slept.
    */
    tv.tv_sec= 0;
    tv.tv_usec= 100000;

    /*
      When using valgrind 2.0 this syscall doesn't get kicked off by a
      signal during shutdown. This results in failing assert
      (Thread_registry::~Thread_registry). Valgrind 2.2 works fine.
    */
    int rc= select(n, &read_fds_arg, 0, 0, &tv);

    if (rc == 0 || rc == -1)
    {
      if (rc == -1 && errno != EINTR)
        log_error("Listener_thread::run(): select() failed, %s",
                  strerror(errno));
      continue;
    }

    for (int socket_index= 0; socket_index < num_sockets; socket_index++)
    {
      /* Assuming that rc > 0 as we asked to wait forever */
      if (FD_ISSET(sockets[socket_index], &read_fds_arg))
      {
        int client_fd= accept(sockets[socket_index], 0, 0);
        /* accept may return -1 (failure or spurious wakeup) */
        if (client_fd >= 0)                    // connection established
        {
          set_no_inherit(client_fd);

          Vio *vio= vio_new(client_fd, socket_index == 0 ?
                            VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
                            socket_index == 0 ? 1 : 0);
          if (vio != 0)
            handle_new_mysql_connection(vio);
          else
          {
            shutdown(client_fd, SHUT_RDWR);
            close(client_fd);
          }
        }
      }
    }
  }

  /* III. Release all resources and exit */

  log_info("Listener_thread::run(): shutdown requested, exiting...");

  for (i= 0; i < num_sockets; i++)
    close(sockets[i]);

#ifndef __WIN__
  unlink(unix_socket_address.sun_path);
#endif

  thread_registry.unregister_thread(&thread_info);
  my_thread_end();
  return;

err:
  // we have to close the ip sockets in case of error
  for (i= 0; i < num_sockets; i++)
    close(sockets[i]);

  thread_registry.unregister_thread(&thread_info);
  thread_registry.request_shutdown();
  my_thread_end();
  return;
}

int Listener_thread::create_tcp_socket()
{
  /* value to be set by setsockopt */
  int arg= 1;

  int ip_socket= socket(AF_INET, SOCK_STREAM, 0);
  if (ip_socket == INVALID_SOCKET)
  {
    log_error("Listener_thead::run(): socket(AF_INET) failed, %s",
              strerror(errno));
    return -1;
  }

  struct sockaddr_in ip_socket_address;
  bzero(&ip_socket_address, sizeof(ip_socket_address));

  ulong im_bind_addr;
  if (options.bind_address != 0)
  {
    if ((im_bind_addr= (ulong) inet_addr(options.bind_address)) == INADDR_NONE)
      im_bind_addr= htonl(INADDR_ANY);
  }
  else
    im_bind_addr= htonl(INADDR_ANY);
  uint im_port= options.port_number;

  ip_socket_address.sin_family= AF_INET;
  ip_socket_address.sin_addr.s_addr= im_bind_addr;

  ip_socket_address.sin_port= (unsigned short)
    htons((unsigned short) im_port);

  setsockopt(ip_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &arg, sizeof(arg));
  if (bind(ip_socket, (struct sockaddr *) &ip_socket_address,
           sizeof(ip_socket_address)))
  {
    log_error("Listener_thread::run(): bind(ip socket) failed, '%s'",
              strerror(errno));
    close(ip_socket);
    return -1;
  }

  if (listen(ip_socket, LISTEN_BACK_LOG_SIZE))
  {
    log_error("Listener_thread::run(): listen(ip socket) failed, %s",
              strerror(errno));
    close(ip_socket);
    return -1;
  }

  /* set the socket nonblocking */
  set_non_blocking(ip_socket);

  /* make sure that instances won't be listening our sockets */
  set_no_inherit(ip_socket);

  FD_SET(ip_socket, &read_fds);
  sockets[num_sockets++]= ip_socket;
  log_info("accepting connections on ip socket (port: %d)", (int) im_port);
  return 0;
}

#ifndef __WIN__
int Listener_thread::
create_unix_socket(struct sockaddr_un &unix_socket_address)
{
  int unix_socket= socket(AF_UNIX, SOCK_STREAM, 0);
  if (unix_socket == INVALID_SOCKET)
  {
    log_error("Listener_thead::run(): socket(AF_UNIX) failed, %s",
              strerror(errno));
    return -1;
  }

  bzero(&unix_socket_address, sizeof(unix_socket_address));

  unix_socket_address.sun_family= AF_UNIX;
  strmake(unix_socket_address.sun_path, options.socket_file_name,
          sizeof(unix_socket_address.sun_path));
  unlink(unix_socket_address.sun_path); // in case we have stale socket file

  /*
    POSIX specifies default permissions for a pathname created by bind
    to be 0777. We need everybody to have access to the socket.
  */
  mode_t old_mask= umask(0);
  if (bind(unix_socket, (struct sockaddr *) &unix_socket_address,
           sizeof(unix_socket_address)))
  {
    log_error("Listener_thread::run(): bind(unix socket) failed, "
              "socket file name is '%s', error '%s'",
              unix_socket_address.sun_path, strerror(errno));
    close(unix_socket);
    return -1;
  }

  umask(old_mask);

  if (listen(unix_socket, LISTEN_BACK_LOG_SIZE))
  {
    log_error("Listener_thread::run(): listen(unix socket) failed, %s",
              strerror(errno));
    close(unix_socket);
    return -1;
  }

  /* set the socket nonblocking */
  set_non_blocking(unix_socket);

  /* make sure that instances won't be listening our sockets */
  set_no_inherit(unix_socket);

  log_info("accepting connections on unix socket '%s'",
           unix_socket_address.sun_path);
  sockets[num_sockets++]= unix_socket;
  FD_SET(unix_socket, &read_fds);
  return 0;
}
#endif

/*
  Create new mysql connection. Created thread is responsible for deletion of
  the Mysql_connection_thread_args and Vio instances passed to it.
  SYNOPSYS
    handle_new_mysql_connection()
*/

void Listener_thread::handle_new_mysql_connection(Vio *vio)
{
  if (Mysql_connection_thread_args *mysql_thread_args=
      new Mysql_connection_thread_args(vio, thread_registry, user_map,
                                       ++total_connection_count,
                                       instance_map)
      )
  {
    /*
      Initialize thread attributes to create detached thread; it seems
      easier to do it ad-hoc than have a global variable for attributes.
    */
    pthread_t mysql_thd_id;
    pthread_attr_t mysql_thd_attr;
    pthread_attr_init(&mysql_thd_attr);
    pthread_attr_setdetachstate(&mysql_thd_attr, PTHREAD_CREATE_DETACHED);
    if (set_stacksize_n_create_thread(&mysql_thd_id, &mysql_thd_attr,
                                      mysql_connection, mysql_thread_args))
    {
      delete mysql_thread_args;
      vio_delete(vio);
      log_error("handle_one_mysql_connection():"
                "set_stacksize_n_create_thread(mysql) failed");
    }
    pthread_attr_destroy(&mysql_thd_attr);
  }
  else
    vio_delete(vio);
}

pthread_handler_t listener(void *arg)
{
  Listener_thread_args *args= (Listener_thread_args *) arg;
  Listener_thread listener(*args);
  listener.run();
  /*
    args is a stack variable because listener thread lives as long as the
    manager process itself
  */
  return 0;
}

<commit_msg>Fix Bug #19044 IM aborts on exit<commit_after>/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

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

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

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

#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
#pragma implementation
#endif

#include "listener.h"
#include "priv.h"
#include <m_string.h>
#include <mysql.h>
#include <violite.h>
#ifndef __WIN__
#include <sys/un.h>
#endif
#include <sys/stat.h>

#include "thread_registry.h"
#include "options.h"
#include "instance_map.h"
#include "log.h"
#include "mysql_connection.h"
#include "portability.h"

static void set_non_blocking(int socket)
{
#ifndef __WIN__
  int flags= fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags | O_NONBLOCK);
#else
  u_long arg= 1;
  ioctlsocket(socket, FIONBIO, &arg);
#endif
}

static void set_no_inherit(int socket)
{
#ifndef __WIN__
  int flags= fcntl(socket, F_GETFD, 0);
  fcntl(socket, F_SETFD, flags | FD_CLOEXEC);
#endif
}

/*
  Listener_thread - incapsulates listening functionality
*/

class Listener_thread: public Listener_thread_args
{
public:
  Listener_thread(const Listener_thread_args &args);
  ~Listener_thread();
  void run();
private:
  static const int LISTEN_BACK_LOG_SIZE= 5;     /* standard backlog size */
  ulong total_connection_count;
  Thread_info thread_info;

  int     sockets[2];
  int     num_sockets;
  fd_set  read_fds;
private:
  void handle_new_mysql_connection(Vio *vio);
  int   create_tcp_socket();
  int   create_unix_socket(struct sockaddr_un &unix_socket_address);
};

Listener_thread::Listener_thread(const Listener_thread_args &args) :
  Listener_thread_args(args.thread_registry, args.options, args.user_map,
                       args.instance_map)
  ,total_connection_count(0)
  ,thread_info(pthread_self())
  ,num_sockets(0)
{
}

Listener_thread::~Listener_thread()
{
}

/*
  Listener_thread::run() - listen all supported sockets and spawn a thread
  to handle incoming connection.
  Using 'die' in case of syscall failure is OK now - we don't hold any
  resources and 'die' kills the signal thread automatically. To be rewritten
  one day.
  See also comments in mysqlmanager.cc to picture general Instance Manager
  architecture.
*/

void Listener_thread::run()
{
  int i, n= 0;

#ifndef __WIN__
  /* we use this var to check whether we are running on LinuxThreads */
  pid_t thread_pid;

  thread_pid= getpid();

  struct sockaddr_un unix_socket_address;
  /* set global variable */
  linuxthreads= (thread_pid != manager_pid);
#endif

  thread_registry.register_thread(&thread_info);

  my_thread_init();

  FD_ZERO(&read_fds);

  /* I. prepare 'listen' sockets */
  if (create_tcp_socket())
    goto err;

#ifndef __WIN__
  if (create_unix_socket(unix_socket_address))
    goto err;
#endif

  /* II. Listen sockets and spawn childs */
  for (i= 0; i < num_sockets; i++)
    n= max(n, sockets[i]);
  n++;

  timeval tv;
  while (!thread_registry.is_shutdown())
  {
    fd_set read_fds_arg= read_fds;
    /*
      We should reintialize timer as on linux it is modified
      to reflect amount of time not slept.
    */
    tv.tv_sec= 0;
    tv.tv_usec= 100000;

    /*
      When using valgrind 2.0 this syscall doesn't get kicked off by a
      signal during shutdown. This results in failing assert
      (Thread_registry::~Thread_registry). Valgrind 2.2 works fine.
    */
    int rc= select(n, &read_fds_arg, 0, 0, &tv);

    if (rc == 0 || rc == -1)
    {
      if (rc == -1 && errno != EINTR)
        log_error("Listener_thread::run(): select() failed, %s",
                  strerror(errno));
      continue;
    }

    for (int socket_index= 0; socket_index < num_sockets; socket_index++)
    {
      /* Assuming that rc > 0 as we asked to wait forever */
      if (FD_ISSET(sockets[socket_index], &read_fds_arg))
      {
        int client_fd= accept(sockets[socket_index], 0, 0);
        /* accept may return -1 (failure or spurious wakeup) */
        if (client_fd >= 0)                    // connection established
        {
          set_no_inherit(client_fd);

          Vio *vio= vio_new(client_fd, socket_index == 0 ?
                            VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
                            socket_index == 0 ? 1 : 0);
          if (vio != 0)
            handle_new_mysql_connection(vio);
          else
          {
            shutdown(client_fd, SHUT_RDWR);
            closesocket(client_fd);
          }
        }
      }
    }
  }

  /* III. Release all resources and exit */

  log_info("Listener_thread::run(): shutdown requested, exiting...");

  for (i= 0; i < num_sockets; i++)
    closesocket(sockets[i]);

#ifndef __WIN__
  unlink(unix_socket_address.sun_path);
#endif

  thread_registry.unregister_thread(&thread_info);
  my_thread_end();
  return;

err:
  // we have to close the ip sockets in case of error
  for (i= 0; i < num_sockets; i++)
    closesocket(sockets[i]);

  thread_registry.unregister_thread(&thread_info);
  thread_registry.request_shutdown();
  my_thread_end();
  return;
}

int Listener_thread::create_tcp_socket()
{
  /* value to be set by setsockopt */
  int arg= 1;

  int ip_socket= socket(AF_INET, SOCK_STREAM, 0);
  if (ip_socket == INVALID_SOCKET)
  {
    log_error("Listener_thead::run(): socket(AF_INET) failed, %s",
              strerror(errno));
    return -1;
  }

  struct sockaddr_in ip_socket_address;
  bzero(&ip_socket_address, sizeof(ip_socket_address));

  ulong im_bind_addr;
  if (options.bind_address != 0)
  {
    if ((im_bind_addr= (ulong) inet_addr(options.bind_address)) == INADDR_NONE)
      im_bind_addr= htonl(INADDR_ANY);
  }
  else
    im_bind_addr= htonl(INADDR_ANY);
  uint im_port= options.port_number;

  ip_socket_address.sin_family= AF_INET;
  ip_socket_address.sin_addr.s_addr= im_bind_addr;

  ip_socket_address.sin_port= (unsigned short)
    htons((unsigned short) im_port);

  setsockopt(ip_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &arg, sizeof(arg));
  if (bind(ip_socket, (struct sockaddr *) &ip_socket_address,
           sizeof(ip_socket_address)))
  {
    log_error("Listener_thread::run(): bind(ip socket) failed, '%s'",
              strerror(errno));
    closesocket(ip_socket);
    return -1;
  }

  if (listen(ip_socket, LISTEN_BACK_LOG_SIZE))
  {
    log_error("Listener_thread::run(): listen(ip socket) failed, %s",
              strerror(errno));
    closesocket(ip_socket);
    return -1;
  }

  /* set the socket nonblocking */
  set_non_blocking(ip_socket);

  /* make sure that instances won't be listening our sockets */
  set_no_inherit(ip_socket);

  FD_SET(ip_socket, &read_fds);
  sockets[num_sockets++]= ip_socket;
  log_info("accepting connections on ip socket (port: %d)", (int) im_port);
  return 0;
}

#ifndef __WIN__
int Listener_thread::
create_unix_socket(struct sockaddr_un &unix_socket_address)
{
  int unix_socket= socket(AF_UNIX, SOCK_STREAM, 0);
  if (unix_socket == INVALID_SOCKET)
  {
    log_error("Listener_thead::run(): socket(AF_UNIX) failed, %s",
              strerror(errno));
    return -1;
  }

  bzero(&unix_socket_address, sizeof(unix_socket_address));

  unix_socket_address.sun_family= AF_UNIX;
  strmake(unix_socket_address.sun_path, options.socket_file_name,
          sizeof(unix_socket_address.sun_path));
  unlink(unix_socket_address.sun_path); // in case we have stale socket file

  /*
    POSIX specifies default permissions for a pathname created by bind
    to be 0777. We need everybody to have access to the socket.
  */
  mode_t old_mask= umask(0);
  if (bind(unix_socket, (struct sockaddr *) &unix_socket_address,
           sizeof(unix_socket_address)))
  {
    log_error("Listener_thread::run(): bind(unix socket) failed, "
              "socket file name is '%s', error '%s'",
              unix_socket_address.sun_path, strerror(errno));
    close(unix_socket);
    return -1;
  }

  umask(old_mask);

  if (listen(unix_socket, LISTEN_BACK_LOG_SIZE))
  {
    log_error("Listener_thread::run(): listen(unix socket) failed, %s",
              strerror(errno));
    close(unix_socket);
    return -1;
  }

  /* set the socket nonblocking */
  set_non_blocking(unix_socket);

  /* make sure that instances won't be listening our sockets */
  set_no_inherit(unix_socket);

  log_info("accepting connections on unix socket '%s'",
           unix_socket_address.sun_path);
  sockets[num_sockets++]= unix_socket;
  FD_SET(unix_socket, &read_fds);
  return 0;
}
#endif

/*
  Create new mysql connection. Created thread is responsible for deletion of
  the Mysql_connection_thread_args and Vio instances passed to it.
  SYNOPSYS
    handle_new_mysql_connection()
*/

void Listener_thread::handle_new_mysql_connection(Vio *vio)
{
  if (Mysql_connection_thread_args *mysql_thread_args=
      new Mysql_connection_thread_args(vio, thread_registry, user_map,
                                       ++total_connection_count,
                                       instance_map)
      )
  {
    /*
      Initialize thread attributes to create detached thread; it seems
      easier to do it ad-hoc than have a global variable for attributes.
    */
    pthread_t mysql_thd_id;
    pthread_attr_t mysql_thd_attr;
    pthread_attr_init(&mysql_thd_attr);
    pthread_attr_setdetachstate(&mysql_thd_attr, PTHREAD_CREATE_DETACHED);
    if (set_stacksize_n_create_thread(&mysql_thd_id, &mysql_thd_attr,
                                      mysql_connection, mysql_thread_args))
    {
      delete mysql_thread_args;
      vio_delete(vio);
      log_error("handle_one_mysql_connection():"
                "set_stacksize_n_create_thread(mysql) failed");
    }
    pthread_attr_destroy(&mysql_thd_attr);
  }
  else
    vio_delete(vio);
}

pthread_handler_t listener(void *arg)
{
  Listener_thread_args *args= (Listener_thread_args *) arg;
  Listener_thread listener(*args);
  listener.run();
  /*
    args is a stack variable because listener thread lives as long as the
    manager process itself
  */
  return 0;
}

<|endoftext|>