<commit_before>/**
 * Copyright © 2016 IBM Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <cstdlib>
#include <experimental/filesystem>
#include <memory>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <xyz/openbmc_project/Control/Device/error.hpp>
#include "sysfs.hpp"
#include "util.hpp"

using namespace phosphor::logging;

std::string findHwmon(const std::string& ofNode)
{
    namespace fs = std::experimental::filesystem;
    static constexpr auto hwmonRoot = "/sys/class/hwmon";
    static constexpr auto ofRoot = "/sys/firmware/devicetree/base";

    fs::path fullOfPath{ofRoot};
    fullOfPath /= ofNode;

    for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
    {
        auto path = hwmonInst.path();
        path /= "of_node";

        if (fs::canonical(path) != fullOfPath)
        {
            continue;
        }

        return hwmonInst.path();
    }

    return std::string();
}

int readSysfsWithCallout(const std::string& root,
                         const std::string& instance,
                         const std::string& type,
                         const std::string& id,
                         const std::string& sensor)
{
    namespace fs = std::experimental::filesystem;

    int value = 0;
    std::ifstream ifs;
    fs::path instancePath{root};
    instancePath /= instance;
    std::string fullPath = make_sysfs_path(instancePath,
                                           type, id, sensor);

    ifs.exceptions(std::ifstream::failbit
                   | std::ifstream::badbit
                   | std::ifstream::eofbit);
    try
    {
        ifs.open(fullPath);
        ifs >> value;
    }
    catch (const std::exception& e)
    {
        // Too many GCC bugs (53984, 66145) to do
        // this the right way...

        // errno should still reflect the error from the failing open
        // or read system calls that got us here.
        auto rc = errno;
        instancePath /= "device";
        phosphor::logging::log<phosphor::logging::level::ERR>(
            strerror(rc),
            phosphor::logging::entry(
                "CALLOUT_DEVICE_PATH=%s",
                fs::canonical(instancePath).c_str()),
            phosphor::logging::entry("CALLOUT_ERRNO=%d", rc));
        exit(EXIT_FAILURE);
    }

    return value;
}

uint64_t writeSysfsWithCallout(const uint64_t& value,
                               const std::string& root,
                               const std::string& instance,
                               const std::string& type,
                               const std::string& id,
                               const std::string& sensor)
{
    namespace fs = std::experimental::filesystem;

    std::string valueStr = std::to_string(value);
    std::ofstream ofs;
    fs::path instancePath{root};
    instancePath /= instance;
    std::string fullPath = make_sysfs_path(instancePath,
                                           type, id, sensor);

    ofs.exceptions(std::ofstream::failbit
                   | std::ofstream::badbit
                   | std::ofstream::eofbit);
    try
    {
        ofs.open(fullPath);
        ofs << valueStr;
    }
    catch (const std::exception& e)
    {
        // errno should still reflect the error from the failing open
        // or write system calls that got us here.
        auto rc = errno;
        instancePath /= "device";
        using namespace sdbusplus::xyz::openbmc_project::Control::Device::Error;
        try
        {
            elog<WriteFailure>(
                xyz::openbmc_project::Control::Device::
                    WriteFailure::CALLOUT_ERRNO(rc),
                xyz::openbmc_project::Control::Device::
                    WriteFailure::CALLOUT_DEVICE_PATH(
                        fs::canonical(instancePath).c_str()));
        }
        catch (WriteFailure& elog)
        {
            commit(elog.name());
        }
        exit(EXIT_FAILURE);
    }

    return value;
}

// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
<commit_msg>Update sysfs reads<commit_after>/**
 * Copyright © 2016 IBM Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <cstdlib>
#include <experimental/filesystem>
#include <memory>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <xyz/openbmc_project/Control/Device/error.hpp>
#include <xyz/openbmc_project/Sensor/Device/error.hpp>
#include "sysfs.hpp"
#include "util.hpp"

using namespace phosphor::logging;

std::string findHwmon(const std::string& ofNode)
{
    namespace fs = std::experimental::filesystem;
    static constexpr auto hwmonRoot = "/sys/class/hwmon";
    static constexpr auto ofRoot = "/sys/firmware/devicetree/base";

    fs::path fullOfPath{ofRoot};
    fullOfPath /= ofNode;

    for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
    {
        auto path = hwmonInst.path();
        path /= "of_node";

        if (fs::canonical(path) != fullOfPath)
        {
            continue;
        }

        return hwmonInst.path();
    }

    return std::string();
}

int readSysfsWithCallout(const std::string& root,
                         const std::string& instance,
                         const std::string& type,
                         const std::string& id,
                         const std::string& sensor)
{
    namespace fs = std::experimental::filesystem;

    int value = 0;
    std::ifstream ifs;
    fs::path instancePath{root};
    instancePath /= instance;
    std::string fullPath = make_sysfs_path(instancePath,
                                           type, id, sensor);

    ifs.exceptions(std::ifstream::failbit
                   | std::ifstream::badbit
                   | std::ifstream::eofbit);
    try
    {
        ifs.open(fullPath);
        ifs >> value;
    }
    catch (const std::exception& e)
    {
        // Too many GCC bugs (53984, 66145) to do
        // this the right way...

        // errno should still reflect the error from the failing open
        // or read system calls that got us here.
        auto rc = errno;
        instancePath /= "device";
        using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
        try
        {
            elog<ReadFailure>(
                xyz::openbmc_project::Sensor::Device::
                    ReadFailure::CALLOUT_ERRNO(rc),
                xyz::openbmc_project::Sensor::Device::
                    ReadFailure::CALLOUT_DEVICE_PATH(
                        fs::canonical(instancePath).c_str()));
        }
        catch (ReadFailure& elog)
        {
            commit(elog.name());
        }
        exit(EXIT_FAILURE);
    }

    return value;
}

uint64_t writeSysfsWithCallout(const uint64_t& value,
                               const std::string& root,
                               const std::string& instance,
                               const std::string& type,
                               const std::string& id,
                               const std::string& sensor)
{
    namespace fs = std::experimental::filesystem;

    std::string valueStr = std::to_string(value);
    std::ofstream ofs;
    fs::path instancePath{root};
    instancePath /= instance;
    std::string fullPath = make_sysfs_path(instancePath,
                                           type, id, sensor);

    ofs.exceptions(std::ofstream::failbit
                   | std::ofstream::badbit
                   | std::ofstream::eofbit);
    try
    {
        ofs.open(fullPath);
        ofs << valueStr;
    }
    catch (const std::exception& e)
    {
        // errno should still reflect the error from the failing open
        // or write system calls that got us here.
        auto rc = errno;
        instancePath /= "device";
        using namespace sdbusplus::xyz::openbmc_project::Control::Device::Error;
        try
        {
            elog<WriteFailure>(
                xyz::openbmc_project::Control::Device::
                    WriteFailure::CALLOUT_ERRNO(rc),
                xyz::openbmc_project::Control::Device::
                    WriteFailure::CALLOUT_DEVICE_PATH(
                        fs::canonical(instancePath).c_str()));
        }
        catch (WriteFailure& elog)
        {
            commit(elog.name());
        }
        exit(EXIT_FAILURE);
    }

    return value;
}

// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
<|endoftext|>


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

using namespace std::string_literals;
namespace fs = std::experimental::filesystem;

namespace sysfs {

static constexpr auto retryableErrors = {
    /*
     * Retry on bus or device errors or timeouts in case
     * they are transient.
     */
    EIO,
    ETIMEDOUT,

    /*
     * Retry CRC errors.
     */
    EBADMSG,

    /*
     * Some hwmon drivers do this when they aren't ready
     * instead of blocking.  Retry.
     */
    EAGAIN,
    /*
     * We'll see this when for example i2c devices are
     * unplugged but the driver is still bound.  Retry
     * rather than exit on the off chance the device is
     * plugged back in and the driver doesn't do a
     * remove/probe.  If a remove does occur, we'll
     * eventually get ENOENT.
     */
    ENXIO,

    /*
     * We can see this from some drivers when we try to do
     * a read in the middle of them being unbound.  The
     * unbinding should complete before the retries are up
     * and kill this process.
     */
    ENODEV,
};

static const auto emptyString = ""s;
static constexpr auto ofRoot = "/sys/firmware/devicetree/base";

std::string findPhandleMatch(
        const std::string& iochanneldir,
        const std::string& phandledir)
{
    // TODO: At the moment this method only supports device trees
    // with iio-hwmon nodes with a single sensor.  Typically
    // device trees are defined with all the iio sensors in a
    // single iio-hwmon node so it would be nice to add support
    // for lists of phandles (with variable sized entries) via
    // libfdt or something like that, so that users are not
    // forced into implementing unusual looking device trees
    // with multiple iio-hwmon nodes - one for each sensor.

    fs::path ioChannelsPath{iochanneldir};
    ioChannelsPath /= "io-channels";

    if (!fs::exists(ioChannelsPath))
    {
        return emptyString;
    }

    uint32_t ioChannelsValue;
    std::ifstream ioChannelsFile(ioChannelsPath);

    ioChannelsFile.read(
            reinterpret_cast<char*>(&ioChannelsValue),
            sizeof(ioChannelsValue));

    for (const auto& ofInst : fs::recursive_directory_iterator(phandledir))
    {
        auto path = ofInst.path();
        if ("phandle" != path.filename())
        {
            continue;
        }
        std::ifstream pHandleFile(path);
        uint32_t pHandleValue;

        pHandleFile.read(
                reinterpret_cast<char*>(&pHandleValue),
                sizeof(pHandleValue));

        if (ioChannelsValue == pHandleValue)
        {
            return path;
        }
    }

    return emptyString;
}

std::string findCalloutPath(const std::string& instancePath)
{
    // Follow the hwmon instance (/sys/class/hwmon/hwmon<N>)
    // /sys/devices symlink.
    fs::path devPath{instancePath};
    devPath /= "device";

    try
    {
        devPath = fs::canonical(devPath);
    }
    catch (const std::system_error& e)
    {
        return emptyString;
    }

    // See if the device is backed by the iio-hwmon driver.
    fs::path p{devPath};
    p /= "driver";
    p = fs::canonical(p);

    if (p.filename() != "iio_hwmon")
    {
        // Not backed by iio-hwmon.  The device pointed to
        // is the callout device.
        return devPath;
    }

    // Find the DT path to the iio-hwmon platform device.
    fs::path ofDevPath{devPath};
    ofDevPath /= "of_node";

    try
    {
        ofDevPath = fs::canonical(ofDevPath);
    }
    catch (const std::system_error& e)
    {
        return emptyString;
    }

    // Search /sys/bus/iio/devices for the phandle in io-channels.
    // If a match is found, use the corresponding /sys/devices
    // iio device as the callout device.
    static constexpr auto iioDevices = "/sys/bus/iio/devices";
    for (const auto& iioDev: fs::recursive_directory_iterator(iioDevices))
    {
        p = iioDev.path();
        p /= "of_node";

        try
        {
            p = fs::canonical(p);
        }
        catch (const std::system_error& e)
        {
            continue;
        }

        auto match = findPhandleMatch(ofDevPath, p);
        auto n = match.rfind('/');
        if (n != std::string::npos)
        {
            // This is the iio device referred to by io-channels.
            // Remove iio:device<N>.
            try
            {
                return fs::canonical(iioDev).parent_path();
            }
            catch (const std::system_error& e)
            {
                return emptyString;
            }
        }
    }

    return emptyString;
}

std::string findHwmon(const std::string& ofNode)
{
    static constexpr auto hwmonRoot = "/sys/class/hwmon";

    fs::path fullOfPath{ofRoot};
    fullOfPath /= ofNode;

    for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
    {
        auto path = hwmonInst.path();
        path /= "of_node";

        try
        {
            path = fs::canonical(path);
        }
        catch (const std::system_error& e)
        {
            // realpath may encounter ENOENT (Hwmon
            // instances have a nasty habit of
            // going away without warning).
            continue;
        }

        if (path == fullOfPath)
        {
            return hwmonInst.path();
        }

        // Try to find HWMON instance via phandle values.
        // Used for IIO device drivers.
        auto matchpath = findPhandleMatch(path, fullOfPath);
        if (!matchpath.empty())
        {
            return hwmonInst.path();
        }
    }

    return emptyString;
}

namespace hwmonio
{

HwmonIO::HwmonIO(const std::string& path) : p(path)
{

}

uint32_t HwmonIO::read(
        const std::string& type,
        const std::string& id,
        const std::string& sensor,
        size_t retries,
        std::chrono::milliseconds delay) const
{
    uint32_t val;
    std::ifstream ifs;
    auto fullPath = sysfs::make_sysfs_path(
            p, type, id, sensor);

    ifs.exceptions(
            std::ifstream::failbit |
                std::ifstream::badbit |
                std::ifstream::eofbit);

    while (true)
    {
        try
        {
            if (!ifs.is_open())
                ifs.open(fullPath);
            ifs.clear();
            ifs.seekg(0);
            ifs >> val;
        }
        catch (const std::exception& e)
        {
            auto rc = errno;

            if (!rc)
            {
                throw;
            }

            if (rc == ENOENT)
            {
                // If the directory disappeared then this application should
                // gracefully exit.  There are race conditions between the
                // unloading of a hwmon driver and the stopping of this service
                // by systemd.  To prevent this application from falsely failing
                // in these scenarios, it will simply exit if the directory or
                // file can not be found.  It is up to the user(s) of this
                // provided hwmon object to log the appropriate errors if the
                // object disappears when it should not.
                exit(0);
            }

            if (0 == std::count(
                        retryableErrors.begin(),
                        retryableErrors.end(),
                        rc) ||
                    !retries)
            {
                // Not a retryable error or out of retries.

                // Work around GCC bugs 53984 and 66145 for callers by
                // explicitly raising system_error here.
                throw std::system_error(rc, std::generic_category());
            }

            --retries;
            std::this_thread::sleep_for(delay);
            continue;
        }
        break;
    }

    return val;
}

void HwmonIO::write(
        uint32_t val,
        const std::string& type,
        const std::string& id,
        const std::string& sensor,
        size_t retries,
        std::chrono::milliseconds delay) const

{
    std::ofstream ofs;
    auto fullPath = sysfs::make_sysfs_path(
            p, type, id, sensor);

    ofs.exceptions(
            std::ofstream::failbit |
                std::ofstream::badbit |
                std::ofstream::eofbit);

    // See comments in the read method for an explanation of the odd exception
    // handling behavior here.

    while (true)
    {
        try
        {
            if (!ofs.is_open())
                ofs.open(fullPath);
            ofs.clear();
            ofs.seekp(0);
            ofs << val;
            ofs.flush();
        }
        catch (const std::exception& e)
        {
            auto rc = errno;

            if (!rc)
            {
                throw;
            }

            if (rc == ENOENT)
            {
                exit(0);
            }

            if (0 == std::count(
                        retryableErrors.begin(),
                        retryableErrors.end(),
                        rc) ||
                    !retries)
            {
                // Not a retryable error or out of retries.

                // Work around GCC bugs 53984 and 66145 for callers by
                // explicitly raising system_error here.
                throw std::system_error(rc, std::generic_category());
            }

            --retries;
            std::this_thread::sleep_for(delay);
            continue;
        }
        break;
    }
}

std::string HwmonIO::path() const
{
    return p;
}

} // namespace hwmonio
}
// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
<commit_msg>Retry on ENODATA errors<commit_after>/**
 * Copyright © 2016 IBM Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <algorithm>
#include <cerrno>
#include <cstdlib>
#include <experimental/filesystem>
#include <fstream>
#include <memory>
#include <thread>
#include "sysfs.hpp"

using namespace std::string_literals;
namespace fs = std::experimental::filesystem;

namespace sysfs {

static constexpr auto retryableErrors = {
    /*
     * Retry on bus or device errors or timeouts in case
     * they are transient.
     */
    EIO,
    ETIMEDOUT,

    /*
     * Retry CRC errors.
     */
    EBADMSG,

    /*
     * Some hwmon drivers do this when they aren't ready
     * instead of blocking.  Retry.
     */
    EAGAIN,
    /*
     * We'll see this when for example i2c devices are
     * unplugged but the driver is still bound.  Retry
     * rather than exit on the off chance the device is
     * plugged back in and the driver doesn't do a
     * remove/probe.  If a remove does occur, we'll
     * eventually get ENOENT.
     */
    ENXIO,

    /*
     * We can see this from some drivers when we try to do
     * a read in the middle of them being unbound.  The
     * unbinding should complete before the retries are up
     * and kill this process.
     */
    ENODEV,

    /*
     * Some devices return this when they are busy doing
     * something else.  Even if being busy isn't the cause,
     * a retry still gives this app a shot at getting data
     * as opposed to failing out on the first try.
     */
    ENODATA,
};

static const auto emptyString = ""s;
static constexpr auto ofRoot = "/sys/firmware/devicetree/base";

std::string findPhandleMatch(
        const std::string& iochanneldir,
        const std::string& phandledir)
{
    // TODO: At the moment this method only supports device trees
    // with iio-hwmon nodes with a single sensor.  Typically
    // device trees are defined with all the iio sensors in a
    // single iio-hwmon node so it would be nice to add support
    // for lists of phandles (with variable sized entries) via
    // libfdt or something like that, so that users are not
    // forced into implementing unusual looking device trees
    // with multiple iio-hwmon nodes - one for each sensor.

    fs::path ioChannelsPath{iochanneldir};
    ioChannelsPath /= "io-channels";

    if (!fs::exists(ioChannelsPath))
    {
        return emptyString;
    }

    uint32_t ioChannelsValue;
    std::ifstream ioChannelsFile(ioChannelsPath);

    ioChannelsFile.read(
            reinterpret_cast<char*>(&ioChannelsValue),
            sizeof(ioChannelsValue));

    for (const auto& ofInst : fs::recursive_directory_iterator(phandledir))
    {
        auto path = ofInst.path();
        if ("phandle" != path.filename())
        {
            continue;
        }
        std::ifstream pHandleFile(path);
        uint32_t pHandleValue;

        pHandleFile.read(
                reinterpret_cast<char*>(&pHandleValue),
                sizeof(pHandleValue));

        if (ioChannelsValue == pHandleValue)
        {
            return path;
        }
    }

    return emptyString;
}

std::string findCalloutPath(const std::string& instancePath)
{
    // Follow the hwmon instance (/sys/class/hwmon/hwmon<N>)
    // /sys/devices symlink.
    fs::path devPath{instancePath};
    devPath /= "device";

    try
    {
        devPath = fs::canonical(devPath);
    }
    catch (const std::system_error& e)
    {
        return emptyString;
    }

    // See if the device is backed by the iio-hwmon driver.
    fs::path p{devPath};
    p /= "driver";
    p = fs::canonical(p);

    if (p.filename() != "iio_hwmon")
    {
        // Not backed by iio-hwmon.  The device pointed to
        // is the callout device.
        return devPath;
    }

    // Find the DT path to the iio-hwmon platform device.
    fs::path ofDevPath{devPath};
    ofDevPath /= "of_node";

    try
    {
        ofDevPath = fs::canonical(ofDevPath);
    }
    catch (const std::system_error& e)
    {
        return emptyString;
    }

    // Search /sys/bus/iio/devices for the phandle in io-channels.
    // If a match is found, use the corresponding /sys/devices
    // iio device as the callout device.
    static constexpr auto iioDevices = "/sys/bus/iio/devices";
    for (const auto& iioDev: fs::recursive_directory_iterator(iioDevices))
    {
        p = iioDev.path();
        p /= "of_node";

        try
        {
            p = fs::canonical(p);
        }
        catch (const std::system_error& e)
        {
            continue;
        }

        auto match = findPhandleMatch(ofDevPath, p);
        auto n = match.rfind('/');
        if (n != std::string::npos)
        {
            // This is the iio device referred to by io-channels.
            // Remove iio:device<N>.
            try
            {
                return fs::canonical(iioDev).parent_path();
            }
            catch (const std::system_error& e)
            {
                return emptyString;
            }
        }
    }

    return emptyString;
}

std::string findHwmon(const std::string& ofNode)
{
    static constexpr auto hwmonRoot = "/sys/class/hwmon";

    fs::path fullOfPath{ofRoot};
    fullOfPath /= ofNode;

    for (const auto& hwmonInst : fs::directory_iterator(hwmonRoot))
    {
        auto path = hwmonInst.path();
        path /= "of_node";

        try
        {
            path = fs::canonical(path);
        }
        catch (const std::system_error& e)
        {
            // realpath may encounter ENOENT (Hwmon
            // instances have a nasty habit of
            // going away without warning).
            continue;
        }

        if (path == fullOfPath)
        {
            return hwmonInst.path();
        }

        // Try to find HWMON instance via phandle values.
        // Used for IIO device drivers.
        auto matchpath = findPhandleMatch(path, fullOfPath);
        if (!matchpath.empty())
        {
            return hwmonInst.path();
        }
    }

    return emptyString;
}

namespace hwmonio
{

HwmonIO::HwmonIO(const std::string& path) : p(path)
{

}

uint32_t HwmonIO::read(
        const std::string& type,
        const std::string& id,
        const std::string& sensor,
        size_t retries,
        std::chrono::milliseconds delay) const
{
    uint32_t val;
    std::ifstream ifs;
    auto fullPath = sysfs::make_sysfs_path(
            p, type, id, sensor);

    ifs.exceptions(
            std::ifstream::failbit |
                std::ifstream::badbit |
                std::ifstream::eofbit);

    while (true)
    {
        try
        {
            if (!ifs.is_open())
                ifs.open(fullPath);
            ifs.clear();
            ifs.seekg(0);
            ifs >> val;
        }
        catch (const std::exception& e)
        {
            auto rc = errno;

            if (!rc)
            {
                throw;
            }

            if (rc == ENOENT)
            {
                // If the directory disappeared then this application should
                // gracefully exit.  There are race conditions between the
                // unloading of a hwmon driver and the stopping of this service
                // by systemd.  To prevent this application from falsely failing
                // in these scenarios, it will simply exit if the directory or
                // file can not be found.  It is up to the user(s) of this
                // provided hwmon object to log the appropriate errors if the
                // object disappears when it should not.
                exit(0);
            }

            if (0 == std::count(
                        retryableErrors.begin(),
                        retryableErrors.end(),
                        rc) ||
                    !retries)
            {
                // Not a retryable error or out of retries.

                // Work around GCC bugs 53984 and 66145 for callers by
                // explicitly raising system_error here.
                throw std::system_error(rc, std::generic_category());
            }

            --retries;
            std::this_thread::sleep_for(delay);
            continue;
        }
        break;
    }

    return val;
}

void HwmonIO::write(
        uint32_t val,
        const std::string& type,
        const std::string& id,
        const std::string& sensor,
        size_t retries,
        std::chrono::milliseconds delay) const

{
    std::ofstream ofs;
    auto fullPath = sysfs::make_sysfs_path(
            p, type, id, sensor);

    ofs.exceptions(
            std::ofstream::failbit |
                std::ofstream::badbit |
                std::ofstream::eofbit);

    // See comments in the read method for an explanation of the odd exception
    // handling behavior here.

    while (true)
    {
        try
        {
            if (!ofs.is_open())
                ofs.open(fullPath);
            ofs.clear();
            ofs.seekp(0);
            ofs << val;
            ofs.flush();
        }
        catch (const std::exception& e)
        {
            auto rc = errno;

            if (!rc)
            {
                throw;
            }

            if (rc == ENOENT)
            {
                exit(0);
            }

            if (0 == std::count(
                        retryableErrors.begin(),
                        retryableErrors.end(),
                        rc) ||
                    !retries)
            {
                // Not a retryable error or out of retries.

                // Work around GCC bugs 53984 and 66145 for callers by
                // explicitly raising system_error here.
                throw std::system_error(rc, std::generic_category());
            }

            --retries;
            std::this_thread::sleep_for(delay);
            continue;
        }
        break;
    }
}

std::string HwmonIO::path() const
{
    return p;
}

} // namespace hwmonio
}
// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
<|endoftext|>


<commit_before><commit_msg>Fixed compatability issue<commit_after><|endoftext|>


<commit_before><commit_msg>recompile dependants even for dependencies which are not resources, e.g. common.glsl<commit_after><|endoftext|>


<commit_before>#include "model.h"
#include "recognition.h"
#include <memory>
#include <algorithm>
#include <vector>

using std::min;
using std::max;
using std::make_shared;
using std::dynamic_pointer_cast;

int FIGURE_SELECT_GAP = -1;
int CLOSED_FIGURE_GAP = -1;
const int TRACK_FIT_GAP = 10;
const int DELETION_MOVE_MINIMAL_LENGTH = 5;
const int DELETION_MOVE_MAX_ANGLE = 30;
const int DELETION_MOVE_MIN_COUNT = 3;
const double SQUARING_MIN_RATIO = 0.8;
const double MIN_FIT_POINTS_AMOUNT = 0.75;

void setRecognitionPreset(RecognitionPreset preset) {
    switch (preset) {
    case RecognitionPreset::Mouse:
        FIGURE_SELECT_GAP = 10;
        CLOSED_FIGURE_GAP = 10;
        break;
    case RecognitionPreset::Touch:
        FIGURE_SELECT_GAP = 30;
        CLOSED_FIGURE_GAP = 50;
        break;
    };
}

BoundingBox getBoundingBox(const Track &track) {
    BoundingBox res;
    res.leftUp = res.rightDown = track[0];
    for (Point p : track.points) {
        res.leftUp.x = min(res.leftUp.x, p.x);
        res.leftUp.y = min(res.leftUp.y, p.y);
        res.rightDown.x = max(res.rightDown.x, p.x);
        res.rightDown.y = max(res.rightDown.y, p.y);
    }
    return res;
}

double getCircumference(const Track &track) {
    double res = 0;
    for (size_t i = 0; i + 1 < track.size(); i++) {
        res += (track[i + 1] - track[i]).length();
    }
    return res;
}
double getClosedCircumference(const Track &track) {
    double res = getCircumference(track);
    res += (track[0] - track[track.size() - 1]).length();
    return res;
}

bool cutToClosed(Track &track) {
    auto &points = track.points;
    auto it = points.begin();
    while (it != points.end() && (points[0] - *it).length() <= CLOSED_FIGURE_GAP) {
        it++;
    }
    while (it != points.end() && (points[0] - *it).length() > CLOSED_FIGURE_GAP) {
        it++;
    }
    if (it == points.end()) {
        return false;
    }
    while (it != points.end() && (points[0] - *it).length() <= CLOSED_FIGURE_GAP) {
        it++;
    }
    points.erase(it, points.end());
    return true;
}

double fitsToTrack(const Track &track, const PFigure &figure) {
    BoundingBox box = getBoundingBox(track);
    double maxDistance = TRACK_FIT_GAP;
    maxDistance = std::min(maxDistance, std::min(box.width(), box.height()) * 0.2);

    int goodCount = 0;
    for (Point p : track.points) {
        goodCount += figure->getApproximateDistanceToBorder(p) <= maxDistance;
    }

    return goodCount * 1.0 / track.size();
}

using namespace figures;

bool isDeletionTrack(const Track &track) {
    int cnt = 0;
    std::cout << "new\n";
    for (int i = 0; i < (int)track.size(); i++) {
        int prevPoint = i - 1;
        while (prevPoint >= 0 && (track[i] - track[prevPoint]).length() < DELETION_MOVE_MINIMAL_LENGTH) {
            prevPoint--;
        }
        int nextPoint = i + 1;
        while (nextPoint < (int)track.size() && (track[i] - track[nextPoint]).length() < DELETION_MOVE_MINIMAL_LENGTH) {
            nextPoint++;
        }
        if (prevPoint >= 0 && nextPoint < (int)track.size()) {
            Point vec1 = track[nextPoint] - track[i];
            Point vec2 = track[prevPoint] - track[i];
            double ang = acos(Point::dotProduct(vec1, vec2) / (vec1.length() * vec2.length()));
            if (ang <= PI * DELETION_MOVE_MAX_ANGLE / 180) {
                cnt++;
                i = nextPoint;
            }
        }
    }
    std::cout << "deletion cnt = " << cnt << "\n";
    return cnt >= DELETION_MOVE_MIN_COUNT;
}

PFigure recognizeConnections(const Track &track, Model &model) {
    Point start = track[0];
    Point end = track[track.size() - 1];

    for (auto it = model.begin(); it != model.end(); it++) {
        PFigure figure = *it;
        auto figA = dynamic_pointer_cast<BoundedFigure>(figure);
        if (!figA) { continue; }
        if (!figure->isInsideOrOnBorder(start)) { continue; }
        for (PFigure figure2 : model) {
            if (figure == figure2) {
                continue;
            }
            auto figB = dynamic_pointer_cast<BoundedFigure>(figure2);
            if (figB && figB->isInsideOrOnBorder(end)) {
                auto result = make_shared<SegmentConnection>(figA, figB);
                model.addFigure(result);
                return result;
            }
        }
    }
    return nullptr;
}

PFigure recognizeGrabs(const Track &track, Model &model) {
    Point start = track[0];
    Point end = track[track.size() - 1];

    for (auto it = model.begin(); it != model.end(); it++) {
        PFigure figure = *it;
        if (figure->getApproximateDistanceToBorder(start) <= FIGURE_SELECT_GAP) { // grabbed
            // recognize deletion
            if (isDeletionTrack(track)) {
                model.removeFigure(it);
                return figure;
            }

            // try connection
            auto figA = dynamic_pointer_cast<BoundedFigure>(figure);
            if (figA) {
                for (PFigure figure2 : model) {
                    if (figure == figure2) {
                        continue;
                    }
                    auto figB = dynamic_pointer_cast<BoundedFigure>(figure2);
                    if (figB && figB->getApproximateDistanceToBorder(end) <= FIGURE_SELECT_GAP) {
                        auto result = make_shared<SegmentConnection>(figA, figB);
                        model.addFigure(result);
                        return result;
                    }
                }
            }

            // now we try translation
            figure->translate(end - start);
            model.recalculate();
            return figure;
        }
    }
    return nullptr;
}

void squareBoundedFigure(PBoundedFigure figure) {
    BoundingBox box = figure->getBoundingBox();
    double siz1 = box.width();
    double siz2 = box.height();
    if (siz1 > siz2) {
        std::swap(siz1, siz2);
    }
    std::cout << "bounded size=" << siz1 << ";" << siz2 << "; k=" << (siz1 / siz2) << "\n";
    if (siz1 / siz2 < SQUARING_MIN_RATIO) { return; }

    double siz = (siz1 + siz2) / 2;
    box.rightDown = box.leftUp + Point(siz, siz);
    figure->setBoundingBox(box);
}

PFigure recognizeClicks(const Point &click, Model &model) {
    for (PFigure figure : model) {
        if (figure->getApproximateDistanceToBorder(click) > FIGURE_SELECT_GAP) {
            continue;
        }
        model.selectedFigure = figure;

        std::shared_ptr<Segment> segm = dynamic_pointer_cast<Segment>(figure);
        if (segm) {
            if ((click - segm->getA()).length() <= FIGURE_SELECT_GAP) {
                segm->setArrowedA(!segm->getArrowedA());
            }
            if ((click - segm->getB()).length() <= FIGURE_SELECT_GAP) {
                segm->setArrowedB(!segm->getArrowedB());
            }
            return segm;
        }
    }
    return nullptr;
}

/*
 * Consider a continuos polyline. This function returns its center of mass.
 * Please note that this differs from center of mass of all points of track,
 * we calculate weighted sum of segments' centers (weight == length of segment)
 */
Point getWeightedCenter(const Track &track) {
    Point result;
    double summaryLength = 0;
    for (size_t i = 0; i < track.size(); i++) {
        Point a = track[i];
        Point b = track[(i + 1) % track.size()];
        Point middle = (a + b) * 0.5;
        double length = (b - a).length();
        result += middle * length;
        summaryLength += length;
    }
    result = result * (1.0 / summaryLength);
    return result;
}

/*
 * Calculates best rectangle which will fit the track
 * For example, it considers that there may be some
 * outliners (they happen near corners when drawing on touch devices)
 * First, it calculate approximate center of the rectangle and then
 * it calculates average 'width' and 'height' of the rectangle.
 * Points which differ from the center no more than width/4 are
 * considered 'horizontal segments' and vice-versa for vertical.
 */
BoundingBox getBestFitRectangle(const Track &track) {
    BoundingBox total = getBoundingBox(track);
    double maxDx = total.width() / 4;
    double maxDy = total.height() / 4;
    Point center = getWeightedCenter(track);

    double sumDx = 0, sumDy = 0;
    int countDx = 0, countDy = 0;
    for (Point p : track.points) {
        double dx = fabs(p.x - center.x);
        double dy = fabs(p.y - center.y);
        if (dx < maxDx && dy >= maxDy) {
            sumDy += dy;
            countDy++;
        }
        if (dy < maxDy && dx >= maxDx) {
            sumDx += dx;
            countDx++;
        }
    }
    Point diff(
        countDx ? sumDx / countDx : maxDx,
        countDy ? sumDy / countDy : maxDy
    );
    return BoundingBox({ center - diff, center + diff });
}

PFigure recognize(const Track &_track, Model &model) {
    if (FIGURE_SELECT_GAP < 0 || CLOSED_FIGURE_GAP < 0) {
        throw std::logic_error("Recognition preset is not selected");
    }

    // this is to preserve the API (const Track&) and make future optimizations possible
    // i.e. avoid copying if it's not necessary
    Track track = _track;
    if (track.empty()) { return nullptr; }

    // Very small tracks are clicks
    if (getClosedCircumference(track) <= CLOSED_FIGURE_GAP) {
        return recognizeClicks(track[0], model);
    }

    // Connecting interior-->interior
    if (PFigure result = recognizeConnections(track, model)) {
        return result;
    }

    // Moving and connecting
    if (PFigure result = recognizeGrabs(track, model)) {
        return result;
    }

    // Drawing new figures
    std::vector<PFigure> candidates;
    if (!cutToClosed(track))  {
        candidates.push_back(make_shared<Segment>(track[0], track[track.size() - 1]));
    } else {
        candidates.push_back(make_shared<Ellipse>(getBoundingBox(track)));
        candidates.push_back(make_shared<Rectangle>(getBestFitRectangle(track)));
    }

    if (candidates.empty()) { return nullptr; }

    std::vector<double> fits;
    for (PFigure figure : candidates) {
        fits.push_back(fitsToTrack(track, figure));
    }
    size_t id = max_element(fits.begin(), fits.end()) - fits.begin();
    std::cout << "max_fit = " << fits[id] << "; id = " << id << "\n";
    if (fits[id] >= MIN_FIT_POINTS_AMOUNT) { // we allow some of points to fall out of our track
        auto boundedFigure = dynamic_pointer_cast<BoundedFigure>(candidates[id]);
        if (boundedFigure) {
            squareBoundedFigure(boundedFigure);
        }
        model.addFigure(candidates[id]);
        return candidates[id];
    }
    return nullptr;
}
<commit_msg>recognizeClicks: little refactoring (arrowing is performed after the loop with selectedFigure)<commit_after>#include "model.h"
#include "recognition.h"
#include <memory>
#include <algorithm>
#include <vector>

using std::min;
using std::max;
using std::make_shared;
using std::dynamic_pointer_cast;

int FIGURE_SELECT_GAP = -1;
int CLOSED_FIGURE_GAP = -1;
const int TRACK_FIT_GAP = 10;
const int DELETION_MOVE_MINIMAL_LENGTH = 5;
const int DELETION_MOVE_MAX_ANGLE = 30;
const int DELETION_MOVE_MIN_COUNT = 3;
const double SQUARING_MIN_RATIO = 0.8;
const double MIN_FIT_POINTS_AMOUNT = 0.75;

void setRecognitionPreset(RecognitionPreset preset) {
    switch (preset) {
    case RecognitionPreset::Mouse:
        FIGURE_SELECT_GAP = 10;
        CLOSED_FIGURE_GAP = 10;
        break;
    case RecognitionPreset::Touch:
        FIGURE_SELECT_GAP = 30;
        CLOSED_FIGURE_GAP = 50;
        break;
    };
}

BoundingBox getBoundingBox(const Track &track) {
    BoundingBox res;
    res.leftUp = res.rightDown = track[0];
    for (Point p : track.points) {
        res.leftUp.x = min(res.leftUp.x, p.x);
        res.leftUp.y = min(res.leftUp.y, p.y);
        res.rightDown.x = max(res.rightDown.x, p.x);
        res.rightDown.y = max(res.rightDown.y, p.y);
    }
    return res;
}

double getCircumference(const Track &track) {
    double res = 0;
    for (size_t i = 0; i + 1 < track.size(); i++) {
        res += (track[i + 1] - track[i]).length();
    }
    return res;
}
double getClosedCircumference(const Track &track) {
    double res = getCircumference(track);
    res += (track[0] - track[track.size() - 1]).length();
    return res;
}

bool cutToClosed(Track &track) {
    auto &points = track.points;
    auto it = points.begin();
    while (it != points.end() && (points[0] - *it).length() <= CLOSED_FIGURE_GAP) {
        it++;
    }
    while (it != points.end() && (points[0] - *it).length() > CLOSED_FIGURE_GAP) {
        it++;
    }
    if (it == points.end()) {
        return false;
    }
    while (it != points.end() && (points[0] - *it).length() <= CLOSED_FIGURE_GAP) {
        it++;
    }
    points.erase(it, points.end());
    return true;
}

double fitsToTrack(const Track &track, const PFigure &figure) {
    BoundingBox box = getBoundingBox(track);
    double maxDistance = TRACK_FIT_GAP;
    maxDistance = std::min(maxDistance, std::min(box.width(), box.height()) * 0.2);

    int goodCount = 0;
    for (Point p : track.points) {
        goodCount += figure->getApproximateDistanceToBorder(p) <= maxDistance;
    }

    return goodCount * 1.0 / track.size();
}

using namespace figures;

bool isDeletionTrack(const Track &track) {
    int cnt = 0;
    std::cout << "new\n";
    for (int i = 0; i < (int)track.size(); i++) {
        int prevPoint = i - 1;
        while (prevPoint >= 0 && (track[i] - track[prevPoint]).length() < DELETION_MOVE_MINIMAL_LENGTH) {
            prevPoint--;
        }
        int nextPoint = i + 1;
        while (nextPoint < (int)track.size() && (track[i] - track[nextPoint]).length() < DELETION_MOVE_MINIMAL_LENGTH) {
            nextPoint++;
        }
        if (prevPoint >= 0 && nextPoint < (int)track.size()) {
            Point vec1 = track[nextPoint] - track[i];
            Point vec2 = track[prevPoint] - track[i];
            double ang = acos(Point::dotProduct(vec1, vec2) / (vec1.length() * vec2.length()));
            if (ang <= PI * DELETION_MOVE_MAX_ANGLE / 180) {
                cnt++;
                i = nextPoint;
            }
        }
    }
    std::cout << "deletion cnt = " << cnt << "\n";
    return cnt >= DELETION_MOVE_MIN_COUNT;
}

PFigure recognizeConnections(const Track &track, Model &model) {
    Point start = track[0];
    Point end = track[track.size() - 1];

    for (auto it = model.begin(); it != model.end(); it++) {
        PFigure figure = *it;
        auto figA = dynamic_pointer_cast<BoundedFigure>(figure);
        if (!figA) { continue; }
        if (!figure->isInsideOrOnBorder(start)) { continue; }
        for (PFigure figure2 : model) {
            if (figure == figure2) {
                continue;
            }
            auto figB = dynamic_pointer_cast<BoundedFigure>(figure2);
            if (figB && figB->isInsideOrOnBorder(end)) {
                auto result = make_shared<SegmentConnection>(figA, figB);
                model.addFigure(result);
                return result;
            }
        }
    }
    return nullptr;
}

PFigure recognizeGrabs(const Track &track, Model &model) {
    Point start = track[0];
    Point end = track[track.size() - 1];

    for (auto it = model.begin(); it != model.end(); it++) {
        PFigure figure = *it;
        if (figure->getApproximateDistanceToBorder(start) <= FIGURE_SELECT_GAP) { // grabbed
            // recognize deletion
            if (isDeletionTrack(track)) {
                model.removeFigure(it);
                return figure;
            }

            // try connection
            auto figA = dynamic_pointer_cast<BoundedFigure>(figure);
            if (figA) {
                for (PFigure figure2 : model) {
                    if (figure == figure2) {
                        continue;
                    }
                    auto figB = dynamic_pointer_cast<BoundedFigure>(figure2);
                    if (figB && figB->getApproximateDistanceToBorder(end) <= FIGURE_SELECT_GAP) {
                        auto result = make_shared<SegmentConnection>(figA, figB);
                        model.addFigure(result);
                        return result;
                    }
                }
            }

            // now we try translation
            figure->translate(end - start);
            model.recalculate();
            return figure;
        }
    }
    return nullptr;
}

void squareBoundedFigure(PBoundedFigure figure) {
    BoundingBox box = figure->getBoundingBox();
    double siz1 = box.width();
    double siz2 = box.height();
    if (siz1 > siz2) {
        std::swap(siz1, siz2);
    }
    std::cout << "bounded size=" << siz1 << ";" << siz2 << "; k=" << (siz1 / siz2) << "\n";
    if (siz1 / siz2 < SQUARING_MIN_RATIO) { return; }

    double siz = (siz1 + siz2) / 2;
    box.rightDown = box.leftUp + Point(siz, siz);
    figure->setBoundingBox(box);
}

PFigure recognizeClicks(const Point &click, Model &model) {
    for (PFigure figure : model) {
        if (figure->getApproximateDistanceToBorder(click) > FIGURE_SELECT_GAP) {
            continue;
        }
        model.selectedFigure = figure;
    }

    std::shared_ptr<Segment> segm = dynamic_pointer_cast<Segment>(model.selectedFigure);
    if (segm) {
        if ((click - segm->getA()).length() <= FIGURE_SELECT_GAP) {
            segm->setArrowedA(!segm->getArrowedA());
        }
        if ((click - segm->getB()).length() <= FIGURE_SELECT_GAP) {
            segm->setArrowedB(!segm->getArrowedB());
        }
        return segm;
    }
    return nullptr;
}

/*
 * Consider a continuos polyline. This function returns its center of mass.
 * Please note that this differs from center of mass of all points of track,
 * we calculate weighted sum of segments' centers (weight == length of segment)
 */
Point getWeightedCenter(const Track &track) {
    Point result;
    double summaryLength = 0;
    for (size_t i = 0; i < track.size(); i++) {
        Point a = track[i];
        Point b = track[(i + 1) % track.size()];
        Point middle = (a + b) * 0.5;
        double length = (b - a).length();
        result += middle * length;
        summaryLength += length;
    }
    result = result * (1.0 / summaryLength);
    return result;
}

/*
 * Calculates best rectangle which will fit the track
 * For example, it considers that there may be some
 * outliners (they happen near corners when drawing on touch devices)
 * First, it calculate approximate center of the rectangle and then
 * it calculates average 'width' and 'height' of the rectangle.
 * Points which differ from the center no more than width/4 are
 * considered 'horizontal segments' and vice-versa for vertical.
 */
BoundingBox getBestFitRectangle(const Track &track) {
    BoundingBox total = getBoundingBox(track);
    double maxDx = total.width() / 4;
    double maxDy = total.height() / 4;
    Point center = getWeightedCenter(track);

    double sumDx = 0, sumDy = 0;
    int countDx = 0, countDy = 0;
    for (Point p : track.points) {
        double dx = fabs(p.x - center.x);
        double dy = fabs(p.y - center.y);
        if (dx < maxDx && dy >= maxDy) {
            sumDy += dy;
            countDy++;
        }
        if (dy < maxDy && dx >= maxDx) {
            sumDx += dx;
            countDx++;
        }
    }
    Point diff(
        countDx ? sumDx / countDx : maxDx,
        countDy ? sumDy / countDy : maxDy
    );
    return BoundingBox({ center - diff, center + diff });
}

PFigure recognize(const Track &_track, Model &model) {
    if (FIGURE_SELECT_GAP < 0 || CLOSED_FIGURE_GAP < 0) {
        throw std::logic_error("Recognition preset is not selected");
    }

    // this is to preserve the API (const Track&) and make future optimizations possible
    // i.e. avoid copying if it's not necessary
    Track track = _track;
    if (track.empty()) { return nullptr; }

    // Very small tracks are clicks
    if (getClosedCircumference(track) <= CLOSED_FIGURE_GAP) {
        return recognizeClicks(track[0], model);
    }

    // Connecting interior-->interior
    if (PFigure result = recognizeConnections(track, model)) {
        return result;
    }

    // Moving and connecting
    if (PFigure result = recognizeGrabs(track, model)) {
        return result;
    }

    // Drawing new figures
    std::vector<PFigure> candidates;
    if (!cutToClosed(track))  {
        candidates.push_back(make_shared<Segment>(track[0], track[track.size() - 1]));
    } else {
        candidates.push_back(make_shared<Ellipse>(getBoundingBox(track)));
        candidates.push_back(make_shared<Rectangle>(getBestFitRectangle(track)));
    }

    if (candidates.empty()) { return nullptr; }

    std::vector<double> fits;
    for (PFigure figure : candidates) {
        fits.push_back(fitsToTrack(track, figure));
    }
    size_t id = max_element(fits.begin(), fits.end()) - fits.begin();
    std::cout << "max_fit = " << fits[id] << "; id = " << id << "\n";
    if (fits[id] >= MIN_FIT_POINTS_AMOUNT) { // we allow some of points to fall out of our track
        auto boundedFigure = dynamic_pointer_cast<BoundedFigure>(candidates[id]);
        if (boundedFigure) {
            squareBoundedFigure(boundedFigure);
        }
        model.addFigure(candidates[id]);
        return candidates[id];
    }
    return nullptr;
}
<|endoftext|>


<commit_before>// Copyright 2011, Tokyo Institute of Technology.
// All rights reserved.
//
// This file is distributed under the license described in
// LICENSE.txt.
//
// Author: Naoya Maruyama (naoya@matsulab.is.titech.ac.jp)

#include "translator/optimizer/optimization_passes.h"
#include "translator/optimizer/optimization_common.h"
#include "translator/rose_util.h"
#include "translator/runtime_builder.h"
#include "translator/translation_util.h"

#include <algorithm>
#include <stack>

namespace si = SageInterface;
namespace sb = SageBuilder;

namespace physis {
namespace translator {
namespace optimizer {
namespace pass {

typedef map<string, SgExpressionVector> GridOffsetMap;

static SgExpression *extract_index_var(SgExpression *offset_dim_exp) {
  SgExpression *off =
      isSgVarRefExp(
          *(NodeQuery::querySubTree(offset_dim_exp,
                                    V_SgVarRefExp).begin()));
  return off;
}

static void build_index_var_list_from_offset_exp(
    SgExpression *offset_expr,
    SgExpressionPtrList *index_va_list) {
  PSAssert(isSgFunctionCallExp(offset_expr));
  SgExpressionPtrList &args =
      isSgFunctionCallExp(offset_expr)->get_args()->get_expressions();
  FOREACH (it, args.begin() + 1, args.end()) {
    index_va_list->push_back(si::copyExpression(
        extract_index_var(*it)));
    LOG_DEBUG() << "Offset expr: "
                << index_va_list->back()->unparseToString()
                << "\n";
  }
}

static bool IsASTNodeDescendant(SgNode *top, SgNode *x) {
  PSAssert(top);
  PSAssert(x);
  do {
    if (top == x) {
      return true;
    }
    x = x->get_parent();
  } while (x != NULL);
  return false;
}

/*!
  Insert the base offset decl, which needs to be after all the used
  variables. The kernel is inlined into the loop, so there is a
  sequence of declarations that are kernel parameters. Find all
  parameter variable delcarations, and append the base offset decl.
*/
static void insert_base_offset(SgBasicBlock *loop_body,
                               SgVariableDeclaration *base_offset_decl,
                               SgInitializedName *gv,
                               SgExpressionPtrList &base_offset_indices) {
  SgDeclarationStatementPtrList decls;
  if (gv) decls.push_back(gv->get_declaration());
  FOREACH (it, base_offset_indices.begin(), base_offset_indices.end()) {
    SgVarRefExp *v = isSgVarRefExp(*it);
    PSAssert(v);
    SgDeclarationStatement *d =
        v->get_symbol()->get_declaration()->get_declaration();
    PSAssert(d);
    if (IsASTNodeDescendant(loop_body, d)) {
      decls.push_back(d);
    }
  }

  FOREACH (it, decls.begin(), decls.end()) {
    LOG_DEBUG() << "Decl: " << (*it)->unparseToString() << "\n";
  }

  // Advance all variables are found
  SgStatement *loop_body_stmt = loop_body->get_statements()[0];
  LOG_DEBUG() << "loop_body_stmt: " << loop_body_stmt->unparseToString() << "\n";
  std::stack<SgStatement*> stack;
  while (decls.size() > 0) {
    if (isSgBasicBlock(loop_body_stmt)) {
      if (si::getNextStatement(loop_body_stmt))
        stack.push(si::getNextStatement(loop_body_stmt));
      loop_body_stmt = si::getFirstStatement(isSgBasicBlock(loop_body_stmt));
    }
    SgDeclarationStatementPtrList::iterator it =
      std::find(decls.begin(), decls.end(), loop_body_stmt);
    if (it != decls.end()) {
      decls.erase(it);
    }
    loop_body_stmt = si::getNextStatement(loop_body_stmt);
    if (!loop_body_stmt) {
      if (stack.size() > 0) {
        loop_body_stmt = stack.top();
        stack.pop();
      } else {
        LOG_ERROR() << "Not all index var declrations found\n";
        PSAssert(0);
      }
    }
    LOG_DEBUG() << "loop_body_stmt: " << loop_body_stmt->unparseToString() << "\n";
  }
  si::insertStatementBefore(loop_body_stmt, base_offset_decl);
}

/*!
  \param gvref Require copying
 */
static SgExpression *build_offset_periodic(SgExpression *offset_exp,
                                           int dim, int index_offset,
                                           SgExpression *gvref,
                                           RuntimeBuilder *builder) {
  /*
    if (index_offset > 0)
    then
       index_offset - dim
    else
       index_offset + dim

  or

    (((offset + dim) % dim) - x)

  */
  SgExpression *offset_d =
      si::copyExpression(
          isSgFunctionCallExp(offset_exp)->get_args()->get_expressions()[dim]);
  SgExpression *offset_periodic = NULL;
#ifdef OFFSET_USE_CONDITIONAL
  SgExpression *wrap_around_exp =
      (index_offset > 0) ?
      (SgExpression*)sb::buildSubtractOp(
          sb::buildIntVal(index_offset),
          builder->BuildGridDim(si::copyExpression(gvref), dim)):
      (SgExpression*)sb::buildAddOp(
          sb::buildIntVal(index_offset),
          builder->BuildGridDim(si::copyExpression(gvref), dim));
  SgExpression *nowrap_around_exp = sb::buildIntVal(index_offset);
  SgExpression *offset_d =
      si::copyExpression(
          isSgFunctionCallExp(offset_exp)->get_args()->get_expressions()[dim]);
  SgExpression *cond_wrap =
      (index_offset > 0) ?
      (SgExpression*)sb::buildGreaterOrEqualOp(
          offset_d,
          builder->BuildGridDim(si::copyExpression(gvref), dim)) :
      (SgExpression*)sb::buildLessThanOp(
          offset_d, sb::buildIntVal(0));
  SgExpression *offset_periodic =
      sb::buildConditionalExp(
          cond_wrap, wrap_around_exp, nowrap_around_exp);
  LOG_DEBUG() << "Offset exp periodic: "
              << offset_periodic->unparseToString() << "\n";
#else
  // Use modulus
  SgExpression *x = sb::buildModOp(
      sb::buildAddOp(offset_d,
                     builder->BuildGridDim(si::copyExpression(gvref), dim)),
      builder->BuildGridDim(si::copyExpression(gvref), dim));
  offset_periodic = sb::buildSubtractOp(
      x,
      si::copyExpression(extract_index_var(offset_d)));
#endif
  LOG_DEBUG() << "Offset exp periodic: "
              << offset_periodic->unparseToString() << "\n";
  return offset_periodic;
}

static void replace_offset(SgVariableDeclaration *base_offset,
                           SgExpressionPtrList &offset_exprs,
                           RuntimeBuilder *builder) {
  FOREACH (it, offset_exprs.begin(), offset_exprs.end()) {
    SgExpression *original_offset_expr = *it;
    GridOffsetAttribute *offset_attr =
        rose_util::GetASTAttribute<GridOffsetAttribute>(
            original_offset_expr);
    SgExpression *gvexpr = offset_attr->gvexpr();
    const StencilIndexList sil = *offset_attr->GetStencilIndexList();
    PSAssert(StencilIndexRegularOrder(sil));
    StencilRegularIndexList sril(sil);
    LOG_DEBUG() << "SRIL: " << sril << "\n";
    SgExpression *dim_offset = sb::buildIntVal(1);
    SgExpression *new_offset_expr = sb::buildVarRefExp(base_offset);
    StencilRegularIndexList::map_t indices = sril.indices();
    FOREACH (it, indices.begin(), indices.end()) {
      int i = it->first;
      int index_offset = it->second;
      LOG_DEBUG() << "index-offset: " << index_offset << "\n";
      if (index_offset != 0) {
        SgExpression *offset_term = NULL;
        if (!offset_attr->periodic()) {
          offset_term = sb::buildIntVal(index_offset);
        } else {
          offset_term = build_offset_periodic(
              original_offset_expr, i,index_offset, gvexpr, builder);
        }
        new_offset_expr = sb::buildAddOp(
            new_offset_expr,
            sb::buildMultiplyOp(dim_offset, offset_term));
      }
      dim_offset = sb::buildMultiplyOp(
          dim_offset,
          builder->BuildGridDim(si::copyExpression(gvexpr), i));
    }
    si::constantFolding(new_offset_expr);
    LOG_DEBUG() << "new offset expression: "
                << new_offset_expr->unparseToString() << "\n";
    si::replaceExpression(original_offset_expr, new_offset_expr);
  }
}

static void build_center_stencil_index_list(StencilIndexList &sil) {
  return;
}

static void do_offset_cse(RuntimeBuilder *builder,
                          SgForStatement *loop,
                          SgExpressionVector &offset_exprs) {
  SgBasicBlock *loop_body = isSgBasicBlock(loop->get_loop_body());
  PSAssert(loop_body);
  SgExpression *offset_expr = offset_exprs[0];
  GridOffsetAttribute *attr =
      rose_util::GetASTAttribute<GridOffsetAttribute>(offset_expr);
  SgExpressionPtrList base_offset_list;
  build_index_var_list_from_offset_exp(offset_expr, &base_offset_list);

  StencilIndexList sil = *attr->GetStencilIndexList();
  StencilIndexListClearOffset(sil);
  PSAssert(attr->gvexpr());
  SgExpression *base_offset = builder->BuildGridOffset(
      si::copyExpression(attr->gvexpr()),
      attr->num_dim(), &base_offset_list,
      true, false, &sil);
  LOG_DEBUG() << "base_offset: " << base_offset->unparseToString() << "\n";
  SgScopeStatement *func_scope =
      si::getEnclosingFunctionDefinition(loop);
  SgVariableDeclaration *base_offset_var
      = sb::buildVariableDeclaration(
          rose_util::generateUniqueName(func_scope),
          BuildIndexType2(rose_util::GetGlobalScope()),
          sb::buildAssignInitializer(
              base_offset, BuildIndexType2(rose_util::GetGlobalScope())),
          func_scope);
  LOG_DEBUG() << "base_offset_var: "
              << base_offset_var->unparseToString() << "\n";

  // NOTE: If the grid reference expression is a SgVarRefExp, it is
  // assumed to be a kernel parameter. In that case, kernel inlining
  // replaces the parameter with a new variable, and the base offset
  // declaration must be placed after that.
  SgInitializedName *gv = NULL;
  if (isSgVarRefExp(attr->gvexpr())) {
    gv = isSgVarRefExp(attr->gvexpr())->get_symbol()->get_declaration();
  }
  insert_base_offset(loop_body, base_offset_var, gv, base_offset_list);
  replace_offset(base_offset_var, offset_exprs, builder);
  return;
}

/*!

  Candidates are grid offset calculation that appears multiple
  times. Those expressions that have the same grid expression are
  considered accessing the same grid. This is a conservative
  assumption, and can be relaxed by more advanced code analysis.
 */
static GridOffsetMap find_candidates(SgForStatement *loop) {
  GridOffsetMap ggm;
  std::vector<SgNode*> offset_exprs =
      rose_util::QuerySubTreeAttribute<GridOffsetAttribute>(loop);
  FOREACH (it, offset_exprs.begin(), offset_exprs.end()) {
    SgExpression *offset_expr = isSgExpression(*it);
    LOG_DEBUG() << "offset: " << offset_expr->unparseToString() << "\n";
    GridOffsetAttribute *attr =
        rose_util::GetASTAttribute<GridOffsetAttribute>(offset_expr);
    PSAssert(attr);
    string gv = attr->gvexpr()->unparseToString();
    LOG_DEBUG() << "gv: " << gv << "\n";
    if (!isContained(ggm, gv)) {
      ggm.insert(std::make_pair(gv, SgExpressionVector()));
    }
    SgExpressionVector &v = ggm[gv];
    v.push_back(offset_expr);
  }

  GridOffsetMap::iterator ggm_it = ggm.begin();
  while (ggm_it != ggm.end()) {
    string grid_str = ggm_it->first;
    SgExpressionVector &get_exprs = ggm_it->second;
    // Needs multiple gets to do CSE
    if (get_exprs.size() <= 1) {
      GridOffsetMap::iterator ggm_it_next = ggm_it;
      ++ggm_it_next;
      ggm.erase(ggm_it);
      ggm_it = ggm_it_next;
      continue;
    }
    LOG_DEBUG() << grid_str
                << " has multiple gets\n";
    ++ggm_it;
  }
  return ggm;
}

/*!
  Assumes kernels are inlined.
*/
void offset_cse(
    SgProject *proj,
    physis::translator::TranslationContext *tx,
    physis::translator::RuntimeBuilder *builder) {
  pre_process(proj, tx, __FUNCTION__);

  vector<SgForStatement*> target_loops = FindInnermostLoops(proj);

  FOREACH (it, target_loops.begin(), target_loops.end()) {
    SgForStatement *target_loop = *it;
    RunKernelLoopAttribute *attr =
        rose_util::GetASTAttribute<RunKernelLoopAttribute>(target_loop);
    if (!attr->IsMain()) continue;
    GridOffsetMap ggm = find_candidates(target_loop);
    FOREACH (it, ggm.begin(), ggm.end()) {
      SgExpressionVector &offset_exprs = it->second;
      do_offset_cse(builder, target_loop, offset_exprs);
    }
  }

  post_process(proj, tx, __FUNCTION__);
}

} // namespace pass
} // namespace optimizer
} // namespace translator
} // namespace physis

<commit_msg>FIX: bug induced because of variable copy removal<commit_after>// Copyright 2011, Tokyo Institute of Technology.
// All rights reserved.
//
// This file is distributed under the license described in
// LICENSE.txt.
//
// Author: Naoya Maruyama (naoya@matsulab.is.titech.ac.jp)

#include "translator/optimizer/optimization_passes.h"
#include "translator/optimizer/optimization_common.h"
#include "translator/rose_util.h"
#include "translator/runtime_builder.h"
#include "translator/translation_util.h"

#include <algorithm>
#include <stack>

namespace si = SageInterface;
namespace sb = SageBuilder;

namespace physis {
namespace translator {
namespace optimizer {
namespace pass {

typedef map<string, SgExpressionVector> GridOffsetMap;

static SgExpression *extract_index_var(SgExpression *offset_dim_exp) {
  SgExpression *off =
      isSgVarRefExp(
          *(NodeQuery::querySubTree(offset_dim_exp,
                                    V_SgVarRefExp).begin()));
  return off;
}

static void build_index_var_list_from_offset_exp(
    SgExpression *offset_expr,
    SgExpressionPtrList *index_va_list) {
  PSAssert(isSgFunctionCallExp(offset_expr));
  SgExpressionPtrList &args =
      isSgFunctionCallExp(offset_expr)->get_args()->get_expressions();
  FOREACH (it, args.begin() + 1, args.end()) {
    index_va_list->push_back(si::copyExpression(
        extract_index_var(*it)));
    LOG_DEBUG() << "Offset expr: "
                << index_va_list->back()->unparseToString()
                << "\n";
  }
}

static bool IsASTNodeDescendant(SgNode *top, SgNode *x) {
  PSAssert(top);
  PSAssert(x);
  do {
    if (top == x) {
      return true;
    }
    x = x->get_parent();
  } while (x != NULL);
  return false;
}

/*!
  \param gvref Require copying
 */
static SgExpression *build_offset_periodic(SgExpression *offset_exp,
                                           int dim, int index_offset,
                                           SgExpression *gvref,
                                           RuntimeBuilder *builder) {
  /*
    if (index_offset > 0)
    then
       index_offset - dim
    else
       index_offset + dim

  or

    (((offset + dim) % dim) - x)

  */
  SgExpression *offset_d =
      si::copyExpression(
          isSgFunctionCallExp(offset_exp)->get_args()->get_expressions()[dim]);
  SgExpression *offset_periodic = NULL;
#ifdef OFFSET_USE_CONDITIONAL
  SgExpression *wrap_around_exp =
      (index_offset > 0) ?
      (SgExpression*)sb::buildSubtractOp(
          sb::buildIntVal(index_offset),
          builder->BuildGridDim(
              sb::buildAddressOfOp(si::copyExpression(gvref)), dim)):
      (SgExpression*)sb::buildAddOp(
          sb::buildIntVal(index_offset),
          builder->BuildGridDim(
              sb::buildAddressOfOp(si::copyExpression(gvref)), dim));
  SgExpression *nowrap_around_exp = sb::buildIntVal(index_offset);
  SgExpression *offset_d =
      si::copyExpression(
          isSgFunctionCallExp(offset_exp)->get_args()->get_expressions()[dim]);
  SgExpression *cond_wrap =
      (index_offset > 0) ?
      (SgExpression*)sb::buildGreaterOrEqualOp(
          offset_d,
          builder->BuildGridDim(
              sb::buildAddressOfOp(si::copyExpression(gvref)), dim)) :
      (SgExpression*)sb::buildLessThanOp(
          offset_d, sb::buildIntVal(0));
  SgExpression *offset_periodic =
      sb::buildConditionalExp(
          cond_wrap, wrap_around_exp, nowrap_around_exp);
  LOG_DEBUG() << "Offset exp periodic: "
              << offset_periodic->unparseToString() << "\n";
#else
  // Use modulus
  SgExpression *x = sb::buildModOp(
      sb::buildAddOp(offset_d,
                     builder->BuildGridDim(
                         sb::buildAddressOfOp(si::copyExpression(gvref)), dim)),
      builder->BuildGridDim(
          sb::buildAddressOfOp(si::copyExpression(gvref)), dim));
  offset_periodic = sb::buildSubtractOp(
      x,
      si::copyExpression(extract_index_var(offset_d)));
#endif
  LOG_DEBUG() << "Offset exp periodic: "
              << offset_periodic->unparseToString() << "\n";
  return offset_periodic;
}

static void replace_offset(SgVariableDeclaration *base_offset,
                           SgExpressionPtrList &offset_exprs,
                           RuntimeBuilder *builder) {
  FOREACH (it, offset_exprs.begin(), offset_exprs.end()) {
    SgExpression *original_offset_expr = *it;
    GridOffsetAttribute *offset_attr =
        rose_util::GetASTAttribute<GridOffsetAttribute>(
            original_offset_expr);
    SgExpression *gvexpr = offset_attr->gvexpr();
    const StencilIndexList sil = *offset_attr->GetStencilIndexList();
    PSAssert(StencilIndexRegularOrder(sil));
    StencilRegularIndexList sril(sil);
    LOG_DEBUG() << "SRIL: " << sril << "\n";
    SgExpression *dim_offset = sb::buildIntVal(1);
    SgExpression *new_offset_expr = sb::buildVarRefExp(base_offset);
    StencilRegularIndexList::map_t indices = sril.indices();
    FOREACH (it, indices.begin(), indices.end()) {
      int i = it->first;
      int index_offset = it->second;
      LOG_DEBUG() << "index-offset: " << index_offset << "\n";
      if (index_offset != 0) {
        SgExpression *offset_term = NULL;
        if (!offset_attr->periodic()) {
          offset_term = sb::buildIntVal(index_offset);
        } else {
          offset_term = build_offset_periodic(
              original_offset_expr, i,index_offset, gvexpr, builder);
        }
        new_offset_expr = sb::buildAddOp(
            new_offset_expr,
            sb::buildMultiplyOp(dim_offset, offset_term));
      }
      dim_offset = sb::buildMultiplyOp(
          dim_offset,
          builder->BuildGridDim(
              sb::buildAddressOfOp(si::copyExpression(gvexpr)), i));
    }
    si::constantFolding(new_offset_expr);
    LOG_DEBUG() << "new offset expression: "
                << new_offset_expr->unparseToString() << "\n";
    si::replaceExpression(original_offset_expr, new_offset_expr);
  }
}

static void build_center_stencil_index_list(StencilIndexList &sil) {
  return;
}

static void do_offset_cse(RuntimeBuilder *builder,
                          SgForStatement *loop,
                          SgExpressionVector &offset_exprs) {
  SgBasicBlock *loop_body = isSgBasicBlock(loop->get_loop_body());
  PSAssert(loop_body);
  SgExpression *offset_expr = offset_exprs[0];
  GridOffsetAttribute *attr =
      rose_util::GetASTAttribute<GridOffsetAttribute>(offset_expr);
  SgExpressionPtrList base_offset_list;
  build_index_var_list_from_offset_exp(offset_expr, &base_offset_list);

  StencilIndexList sil = *attr->GetStencilIndexList();
  StencilIndexListClearOffset(sil);
  PSAssert(attr->gvexpr());
  SgExpression *base_offset = builder->BuildGridOffset(
      sb::buildAddressOfOp(si::copyExpression(attr->gvexpr())),
      attr->num_dim(), &base_offset_list,
      true, false, &sil);
  LOG_DEBUG() << "base_offset: " << base_offset->unparseToString() << "\n";
  SgScopeStatement *func_scope =
      si::getEnclosingFunctionDefinition(loop);
  SgVariableDeclaration *base_offset_var
      = sb::buildVariableDeclaration(
          rose_util::generateUniqueName(func_scope),
          BuildIndexType2(rose_util::GetGlobalScope()),
          sb::buildAssignInitializer(
              base_offset, BuildIndexType2(rose_util::GetGlobalScope())),
          func_scope);
  LOG_DEBUG() << "base_offset_var: "
              << base_offset_var->unparseToString() << "\n";

  si::insertStatementBefore(loop_body->get_statements()[0],
                            base_offset_var);
  replace_offset(base_offset_var, offset_exprs, builder);
  return;
}

/*!

  Candidates are grid offset calculation that appears multiple
  times. Those expressions that have the same grid expression are
  considered accessing the same grid. This is a conservative
  assumption, and can be relaxed by more advanced code analysis.
 */
static GridOffsetMap find_candidates(SgForStatement *loop) {
  GridOffsetMap ggm;
  std::vector<SgNode*> offset_exprs =
      rose_util::QuerySubTreeAttribute<GridOffsetAttribute>(loop);
  FOREACH (it, offset_exprs.begin(), offset_exprs.end()) {
    SgExpression *offset_expr = isSgExpression(*it);
    LOG_DEBUG() << "offset: " << offset_expr->unparseToString() << "\n";
    GridOffsetAttribute *attr =
        rose_util::GetASTAttribute<GridOffsetAttribute>(offset_expr);
    PSAssert(attr);
    string gv = attr->gvexpr()->unparseToString();
    LOG_DEBUG() << "gv: " << gv << "\n";
    if (!isContained(ggm, gv)) {
      ggm.insert(std::make_pair(gv, SgExpressionVector()));
    }
    SgExpressionVector &v = ggm[gv];
    v.push_back(offset_expr);
  }

  GridOffsetMap::iterator ggm_it = ggm.begin();
  while (ggm_it != ggm.end()) {
    string grid_str = ggm_it->first;
    SgExpressionVector &get_exprs = ggm_it->second;
    // Needs multiple gets to do CSE
    if (get_exprs.size() <= 1) {
      GridOffsetMap::iterator ggm_it_next = ggm_it;
      ++ggm_it_next;
      ggm.erase(ggm_it);
      ggm_it = ggm_it_next;
      continue;
    }
    LOG_DEBUG() << grid_str
                << " has multiple gets\n";
    ++ggm_it;
  }
  return ggm;
}

/*!
  Assumes kernels are inlined.
*/
void offset_cse(
    SgProject *proj,
    physis::translator::TranslationContext *tx,
    physis::translator::RuntimeBuilder *builder) {
  pre_process(proj, tx, __FUNCTION__);

  vector<SgForStatement*> target_loops = FindInnermostLoops(proj);

  FOREACH (it, target_loops.begin(), target_loops.end()) {
    SgForStatement *target_loop = *it;
    RunKernelLoopAttribute *attr =
        rose_util::GetASTAttribute<RunKernelLoopAttribute>(target_loop);
    if (!attr->IsMain()) continue;
    GridOffsetMap ggm = find_candidates(target_loop);
    FOREACH (it, ggm.begin(), ggm.end()) {
      SgExpressionVector &offset_exprs = it->second;
      do_offset_cse(builder, target_loop, offset_exprs);
    }
  }

  post_process(proj, tx, __FUNCTION__);
}

} // namespace pass
} // namespace optimizer
} // namespace translator
} // namespace physis

<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cassert>
#include <xf86drm.h>
#include <xf86drmMode.h>

#include <kms++/kms++.h>

using namespace std;

namespace kms
{

struct EncoderPriv
{
	drmModeEncoderPtr drm_encoder;
};

static const map<int, string> encoder_types = {
#define DEF_ENC(c) { DRM_MODE_ENCODER_##c, #c }
	DEF_ENC(NONE),
	DEF_ENC(DAC),
	DEF_ENC(TMDS),
	DEF_ENC(LVDS),
	DEF_ENC(TVDAC),
	DEF_ENC(VIRTUAL),
	DEF_ENC(DSI),
	{ 7, "DPMST" },
#undef DEF_ENC
};

Encoder::Encoder(Card &card, uint32_t id, uint32_t idx)
	:DrmPropObject(card, id, DRM_MODE_OBJECT_ENCODER, idx)
{
	m_priv = new EncoderPriv();
	m_priv->drm_encoder = drmModeGetEncoder(this->card().fd(), this->id());
	assert(m_priv->drm_encoder);
}

Encoder::~Encoder()
{
	drmModeFreeEncoder(m_priv->drm_encoder);
	delete m_priv;
}

void Encoder::refresh()
{
	drmModeFreeEncoder(m_priv->drm_encoder);

	m_priv->drm_encoder = drmModeGetEncoder(this->card().fd(), this->id());
	assert(m_priv->drm_encoder);
}

Crtc* Encoder::get_crtc() const
{
	if (m_priv->drm_encoder->crtc_id)
		return card().get_crtc(m_priv->drm_encoder->crtc_id);
	else
		return 0;
}

vector<Crtc*> Encoder::get_possible_crtcs() const
{
	unsigned bits = m_priv->drm_encoder->possible_crtcs;
	vector<Crtc*> crtcs;

	for (int idx = 0; bits; idx++, bits >>= 1) {
		if ((bits & 1) == 0)
			continue;

		auto crtc = card().get_crtcs()[idx];
		crtcs.push_back(crtc);
	}

	return crtcs;
}

const string& Encoder::get_encoder_type() const
{
	return encoder_types.at(m_priv->drm_encoder->encoder_type);
}

}
<commit_msg>Add DPI encoder<commit_after>#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cassert>
#include <xf86drm.h>
#include <xf86drmMode.h>

#include <kms++/kms++.h>

using namespace std;

namespace kms
{

struct EncoderPriv
{
	drmModeEncoderPtr drm_encoder;
};

static const map<int, string> encoder_types = {
#define DEF_ENC(c) { DRM_MODE_ENCODER_##c, #c }
	DEF_ENC(NONE),
	DEF_ENC(DAC),
	DEF_ENC(TMDS),
	DEF_ENC(LVDS),
	DEF_ENC(TVDAC),
	DEF_ENC(VIRTUAL),
	DEF_ENC(DSI),
	{ 7, "DPMST" },
	{ 8, "DPI" },
#undef DEF_ENC
};

Encoder::Encoder(Card &card, uint32_t id, uint32_t idx)
	:DrmPropObject(card, id, DRM_MODE_OBJECT_ENCODER, idx)
{
	m_priv = new EncoderPriv();
	m_priv->drm_encoder = drmModeGetEncoder(this->card().fd(), this->id());
	assert(m_priv->drm_encoder);
}

Encoder::~Encoder()
{
	drmModeFreeEncoder(m_priv->drm_encoder);
	delete m_priv;
}

void Encoder::refresh()
{
	drmModeFreeEncoder(m_priv->drm_encoder);

	m_priv->drm_encoder = drmModeGetEncoder(this->card().fd(), this->id());
	assert(m_priv->drm_encoder);
}

Crtc* Encoder::get_crtc() const
{
	if (m_priv->drm_encoder->crtc_id)
		return card().get_crtc(m_priv->drm_encoder->crtc_id);
	else
		return 0;
}

vector<Crtc*> Encoder::get_possible_crtcs() const
{
	unsigned bits = m_priv->drm_encoder->possible_crtcs;
	vector<Crtc*> crtcs;

	for (int idx = 0; bits; idx++, bits >>= 1) {
		if ((bits & 1) == 0)
			continue;

		auto crtc = card().get_crtcs()[idx];
		crtcs.push_back(crtc);
	}

	return crtcs;
}

const string& Encoder::get_encoder_type() const
{
	return encoder_types.at(m_priv->drm_encoder->encoder_type);
}

}
<|endoftext|>


<commit_before>#include "notifications.h"
#include "display.h"
#include "space.h"
#include "window.h"
#include "border.h"

extern kwm_screen KWMScreen;
extern kwm_toggles KWMToggles;
extern kwm_tiling KWMTiling;
extern kwm_focus KWMFocus;
extern kwm_thread KWMThread;
extern kwm_mode KWMMode;

void FocusedAXObserverCallback(AXObserverRef Observer, AXUIElementRef Element, CFStringRef Notification, void *ContextData)
{
    pthread_mutex_lock(&KWMThread.Lock);

    window_info *Window = KWMFocus.Window;
    if(Window && CFEqual(Notification, kAXTitleChangedNotification))
        Window->Name = GetWindowTitle(Element);
    else if(CFEqual(Notification, kAXFocusedWindowChangedNotification))
    {
        if(!Window || Window->WID != GetWindowIDFromRef(Element))
        {
            DEBUG("Element: " << GetWindowTitle(Element))
            window_info *OSXWindow = GetWindowByID(GetWindowIDFromRef(Element));
            screen_info *OSXScreen = GetDisplayOfWindow(OSXWindow);
            if(OSXWindow && OSXScreen)
            {
                screen_info *ScreenOfWindow = GetDisplayOfWindow(Window);
                UpdateActiveWindowList(ScreenOfWindow);

                if(ScreenOfWindow && Window &&
                   GetWindowByID(Window->WID) == NULL &&
                   OSXScreen != ScreenOfWindow)
                {
                    space_info *SpaceOfWindow = GetActiveSpaceOfScreen(ScreenOfWindow);
                    if(SpaceOfWindow->Mode == SpaceModeBSP)
                        RemoveWindowFromBSPTree(ScreenOfWindow, Window->WID, false, false);
                    else if(SpaceOfWindow->Mode == SpaceModeMonocle)
                        RemoveWindowFromMonocleTree(ScreenOfWindow, Window->WID, false);

                    SpaceOfWindow->FocusedWindowID = 0;
                }

                GiveFocusToScreen(OSXScreen->ID, NULL, false, false);
                SetKwmFocus(Element);
                if(OSXScreen == ScreenOfWindow)
                    KWMFocus.InsertionPoint = KWMFocus.Cache;
            }
        }
    }
    else if(CFEqual(Notification, kAXWindowResizedNotification) ||
            CFEqual(Notification, kAXWindowMovedNotification) ||
            CFEqual(Notification, kAXWindowMiniaturizedNotification))
    {
        UpdateBorder("focused");
        if (Window && Window->WID == KWMScreen.MarkedWindow)
            UpdateBorder("marked");
    }

    pthread_mutex_unlock(&KWMThread.Lock);
}

void DestroyApplicationNotifications()
{
    if(!KWMFocus.Observer)
        return;

    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowMiniaturizedNotification);
    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowMovedNotification);
    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowResizedNotification);
    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXTitleChangedNotification);
    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXFocusedWindowChangedNotification);
    CFRunLoopRemoveSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(KWMFocus.Observer), kCFRunLoopDefaultMode);

    CFRelease(KWMFocus.Observer);
    KWMFocus.Observer = NULL;
    CFRelease(KWMFocus.Application);
    KWMFocus.Application = NULL;
}

void CreateApplicationNotifications()
{
    DestroyApplicationNotifications();

    if(KWMFocus.Window)
    {
        KWMFocus.Application = AXUIElementCreateApplication(KWMFocus.Window->PID);
        if(!KWMFocus.Application)
            return;

        AXError Error = AXObserverCreate(KWMFocus.Window->PID, FocusedAXObserverCallback, &KWMFocus.Observer);
        if(Error == kAXErrorSuccess)
        {
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowMiniaturizedNotification, NULL);
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowMovedNotification, NULL);
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowResizedNotification, NULL);
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXTitleChangedNotification, NULL);
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXFocusedWindowChangedNotification, NULL);
            CFRunLoopAddSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(KWMFocus.Observer), kCFRunLoopDefaultMode);
        }
    }
}
<commit_msg>make sure ScreenOfWindow is not null<commit_after>#include "notifications.h"
#include "display.h"
#include "space.h"
#include "window.h"
#include "border.h"

extern kwm_screen KWMScreen;
extern kwm_toggles KWMToggles;
extern kwm_tiling KWMTiling;
extern kwm_focus KWMFocus;
extern kwm_thread KWMThread;
extern kwm_mode KWMMode;

void FocusedAXObserverCallback(AXObserverRef Observer, AXUIElementRef Element, CFStringRef Notification, void *ContextData)
{
    pthread_mutex_lock(&KWMThread.Lock);

    window_info *Window = KWMFocus.Window;
    if(Window && CFEqual(Notification, kAXTitleChangedNotification))
        Window->Name = GetWindowTitle(Element);
    else if(CFEqual(Notification, kAXFocusedWindowChangedNotification))
    {
        if(!Window || Window->WID != GetWindowIDFromRef(Element))
        {
            DEBUG("Element: " << GetWindowTitle(Element))
            window_info *OSXWindow = GetWindowByID(GetWindowIDFromRef(Element));
            screen_info *OSXScreen = GetDisplayOfWindow(OSXWindow);
            if(OSXWindow && OSXScreen)
            {
                screen_info *ScreenOfWindow = GetDisplayOfWindow(Window);
                if(ScreenOfWindow)
                    UpdateActiveWindowList(ScreenOfWindow);

                if(ScreenOfWindow && Window &&
                   GetWindowByID(Window->WID) == NULL &&
                   OSXScreen != ScreenOfWindow)
                {
                    space_info *SpaceOfWindow = GetActiveSpaceOfScreen(ScreenOfWindow);
                    if(SpaceOfWindow->Mode == SpaceModeBSP)
                        RemoveWindowFromBSPTree(ScreenOfWindow, Window->WID, false, false);
                    else if(SpaceOfWindow->Mode == SpaceModeMonocle)
                        RemoveWindowFromMonocleTree(ScreenOfWindow, Window->WID, false);

                    SpaceOfWindow->FocusedWindowID = 0;
                }

                GiveFocusToScreen(OSXScreen->ID, NULL, false, false);
                SetKwmFocus(Element);
                if(OSXScreen == ScreenOfWindow)
                    KWMFocus.InsertionPoint = KWMFocus.Cache;
            }
        }
    }
    else if(CFEqual(Notification, kAXWindowResizedNotification) ||
            CFEqual(Notification, kAXWindowMovedNotification) ||
            CFEqual(Notification, kAXWindowMiniaturizedNotification))
    {
        UpdateBorder("focused");
        if (Window && Window->WID == KWMScreen.MarkedWindow)
            UpdateBorder("marked");
    }

    pthread_mutex_unlock(&KWMThread.Lock);
}

void DestroyApplicationNotifications()
{
    if(!KWMFocus.Observer)
        return;

    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowMiniaturizedNotification);
    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowMovedNotification);
    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowResizedNotification);
    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXTitleChangedNotification);
    AXObserverRemoveNotification(KWMFocus.Observer, KWMFocus.Application, kAXFocusedWindowChangedNotification);
    CFRunLoopRemoveSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(KWMFocus.Observer), kCFRunLoopDefaultMode);

    CFRelease(KWMFocus.Observer);
    KWMFocus.Observer = NULL;
    CFRelease(KWMFocus.Application);
    KWMFocus.Application = NULL;
}

void CreateApplicationNotifications()
{
    DestroyApplicationNotifications();

    if(KWMFocus.Window)
    {
        KWMFocus.Application = AXUIElementCreateApplication(KWMFocus.Window->PID);
        if(!KWMFocus.Application)
            return;

        AXError Error = AXObserverCreate(KWMFocus.Window->PID, FocusedAXObserverCallback, &KWMFocus.Observer);
        if(Error == kAXErrorSuccess)
        {
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowMiniaturizedNotification, NULL);
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowMovedNotification, NULL);
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXWindowResizedNotification, NULL);
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXTitleChangedNotification, NULL);
            AXObserverAddNotification(KWMFocus.Observer, KWMFocus.Application, kAXFocusedWindowChangedNotification, NULL);
            CFRunLoopAddSource(CFRunLoopGetMain(), AXObserverGetRunLoopSource(KWMFocus.Observer), kCFRunLoopDefaultMode);
        }
    }
}
<|endoftext|>


<commit_before>/**
 * @author Andre Anjos <andre.anjos@idiap.ch>
 * @date Thu  7 Nov 13:50:16 2013
 *
 * @brief Binds configuration information available from bob
 */

#include <Python.h>

#include <xbob.core/config.h>

#include <bob/config.h>

#include <string>
#include <cstdlib>
#include <blitz/blitz.h>
#include <boost/preprocessor/stringize.hpp>
#include <boost/version.hpp>
#include <boost/format.hpp>
#if WITH_PERFTOOLS
#include <google/tcmalloc.h>
#endif

#ifdef NO_IMPORT_ARRAY
#undef NO_IMPORT_ARRAY
#endif
#include <xbob.blitz/capi.h>
#include <xbob.blitz/cleanup.h>

static int dict_steal(PyObject* d, const char* key, PyObject* value) {
  if (!value) return 0;
  int retval = PyDict_SetItemString(d, key, value);
  Py_DECREF(value);
  if (retval == 0) return 1; //all good
  return 0; //a problem occurred
}

/**
 * Describes the version of Boost libraries installed
 */
static PyObject* boost_version() {
  boost::format f("%d.%d.%d");
  f % (BOOST_VERSION / 100000);
  f % (BOOST_VERSION / 100 % 1000);
  f % (BOOST_VERSION % 100);
  return Py_BuildValue("s", f.str().c_str());
}

/**
 * Describes the compiler version
 */
static PyObject* compiler_version() {
# if defined(__GNUC__) && !defined(__llvm__)
  boost::format f("%s.%s.%s");
  f % BOOST_PP_STRINGIZE(__GNUC__);
  f % BOOST_PP_STRINGIZE(__GNUC_MINOR__);
  f % BOOST_PP_STRINGIZE(__GNUC_PATCHLEVEL__);
  return Py_BuildValue("ss", "gcc", f.str().c_str());
# elif defined(__llvm__) && !defined(__clang__)
  return Py_BuildValue("ss", "llvm-gcc", __VERSION__);
# elif defined(__clang__)
  return Py_BuildValue("ss", "clang", __clang_version__);
# else
  return Py_BuildValue("s", "unsupported");
# endif
}

/**
 * Python version with which we compiled the extensions
 */
static PyObject* python_version() {
  boost::format f("%s.%s.%s");
  f % BOOST_PP_STRINGIZE(PY_MAJOR_VERSION);
  f % BOOST_PP_STRINGIZE(PY_MINOR_VERSION);
  f % BOOST_PP_STRINGIZE(PY_MICRO_VERSION);
  return Py_BuildValue("s", f.str().c_str());
}

/**
 * Google profiler version, if available
 */
static PyObject* perftools_version() {
#if WITH_PERFTOOLS
  boost::format f("%s.%s.%s");
  f % BOOST_PP_STRINGIZE(TC_VERSION_MAJOR);
  f % BOOST_PP_STRINGIZE(TC_VERSION_MINOR);
  if (std::strlen(TC_VERSION_PATCH) == 0) f % "0";
  else f % BOOST_PP_STRINGIZE(TC_VERSION_PATCH);
  return Py_BuildValue("s", f.str().c_str());
#else
  return Py_BuildValue("s", "unavailable");
#endif
}

/**
 * Bob version, API version and platform
 */
static PyObject* bob_version() {
  return Py_BuildValue("sis", BOB_VERSION, BOB_API_VERSION, BOB_PLATFORM);
}

static PyObject* build_version_dictionary() {

  PyObject* retval = PyDict_New();
  if (!retval) return 0;

  if (!dict_steal(retval, "Boost", boost_version())) {
    Py_DECREF(retval);
    return 0;
  }

  if (!dict_steal(retval, "Compiler", compiler_version())) {
    Py_DECREF(retval);
    return 0;
  }

  if (!dict_steal(retval, "Python", python_version())) {
    Py_DECREF(retval);
    return 0;
  }

  if (!dict_steal(retval, "Google Perftools", perftools_version())) {
    Py_DECREF(retval);
    return 0;
  }

  if (!dict_steal(retval, "Bob", bob_version())) {
    Py_DECREF(retval);
    return 0;
  }

  return retval;
}

static PyMethodDef module_methods[] = {
    {0}  /* Sentinel */
};

PyDoc_STRVAR(module_docstr,
"Information about software used to compile the C++ Bob API"
);

#if PY_VERSION_HEX >= 0x03000000
static PyModuleDef module_definition = {
  PyModuleDef_HEAD_INIT,
  XBOB_EXT_MODULE_NAME,
  module_docstr,
  -1,
  module_methods,
  0, 0, 0, 0
};
#endif

static PyObject* create_module (void) {

# if PY_VERSION_HEX >= 0x03000000
  PyObject* m = PyModule_Create(&module_definition);
# else
  PyObject* m = Py_InitModule3(XBOB_EXT_MODULE_NAME, module_methods, module_docstr);
# endif
  if (!m) return 0;
  auto m_ = make_safe(m); ///< protects against early returns

  /* register version numbers and constants */
  if (PyModule_AddStringConstant(m, "module", XBOB_EXT_MODULE_VERSION) < 0)
    return 0;

  if (PyModule_AddIntConstant(m, "api", XBOB_CORE_API_VERSION) < 0)
    return 0;

  PyObject* externals = build_version_dictionary();
  if (!externals) return 0;
  if (PyModule_AddObject(m, "externals", externals) < 0) return 0;

  if (import_xbob_blitz() < 0) return 0;

  Py_INCREF(m);
  return m;

}

PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) {
# if PY_VERSION_HEX >= 0x03000000
  return
# endif
    create_module();
}
<commit_msg>Use make_safe(); Include xbob.blitz version<commit_after>/**
 * @author Andre Anjos <andre.anjos@idiap.ch>
 * @date Thu  7 Nov 13:50:16 2013
 *
 * @brief Binds configuration information available from bob
 */

#include <Python.h>

#include <xbob.core/config.h>

#include <bob/config.h>

#include <string>
#include <cstdlib>
#include <blitz/blitz.h>
#include <boost/preprocessor/stringize.hpp>
#include <boost/version.hpp>
#include <boost/format.hpp>
#if WITH_PERFTOOLS
#include <google/tcmalloc.h>
#endif

#ifdef NO_IMPORT_ARRAY
#undef NO_IMPORT_ARRAY
#endif
#include <xbob.blitz/capi.h>
#include <xbob.blitz/cleanup.h>

static int dict_set(PyObject* d, const char* key, const char* value) {
  PyObject* v = Py_BuildValue("s", value);
  if (!v) return 0;
  int retval = PyDict_SetItemString(d, key, v);
  Py_DECREF(v);
  if (retval == 0) return 1; //all good
  return 0; //a problem occurred
}

static int dict_steal(PyObject* d, const char* key, PyObject* value) {
  if (!value) return 0;
  int retval = PyDict_SetItemString(d, key, value);
  Py_DECREF(value);
  if (retval == 0) return 1; //all good
  return 0; //a problem occurred
}

/**
 * Describes the version of Boost libraries installed
 */
static PyObject* boost_version() {
  boost::format f("%d.%d.%d");
  f % (BOOST_VERSION / 100000);
  f % (BOOST_VERSION / 100 % 1000);
  f % (BOOST_VERSION % 100);
  return Py_BuildValue("s", f.str().c_str());
}

/**
 * Describes the compiler version
 */
static PyObject* compiler_version() {
# if defined(__GNUC__) && !defined(__llvm__)
  boost::format f("%s.%s.%s");
  f % BOOST_PP_STRINGIZE(__GNUC__);
  f % BOOST_PP_STRINGIZE(__GNUC_MINOR__);
  f % BOOST_PP_STRINGIZE(__GNUC_PATCHLEVEL__);
  return Py_BuildValue("ss", "gcc", f.str().c_str());
# elif defined(__llvm__) && !defined(__clang__)
  return Py_BuildValue("ss", "llvm-gcc", __VERSION__);
# elif defined(__clang__)
  return Py_BuildValue("ss", "clang", __clang_version__);
# else
  return Py_BuildValue("s", "unsupported");
# endif
}

/**
 * Python version with which we compiled the extensions
 */
static PyObject* python_version() {
  boost::format f("%s.%s.%s");
  f % BOOST_PP_STRINGIZE(PY_MAJOR_VERSION);
  f % BOOST_PP_STRINGIZE(PY_MINOR_VERSION);
  f % BOOST_PP_STRINGIZE(PY_MICRO_VERSION);
  return Py_BuildValue("s", f.str().c_str());
}

/**
 * Bob version, API version and platform
 */
static PyObject* bob_version() {
  return Py_BuildValue("sis", BOB_VERSION, BOB_API_VERSION, BOB_PLATFORM);
}

/**
 * Numpy version
 */
static PyObject* numpy_version() {
  return Py_BuildValue("{ssss}", "abi", BOOST_PP_STRINGIZE(NPY_VERSION),
      "api", BOOST_PP_STRINGIZE(NPY_API_VERSION));
}

/**
 * xbob.blitz c/c++ api version
 */
static PyObject* xbob_blitz_version() {
  return Py_BuildValue("{ss}", "api", BOOST_PP_STRINGIZE(XBOB_BLITZ_API_VERSION));
}

static PyObject* build_version_dictionary() {

  PyObject* retval = PyDict_New();
  if (!retval) return 0;
  auto retval_ = make_safe(retval);

  if (!dict_set(retval, "Blitz++", BZ_VERSION)) return 0;
  if (!dict_steal(retval, "Boost", boost_version())) return 0;
  if (!dict_steal(retval, "Compiler", compiler_version())) return 0;
  if (!dict_steal(retval, "Python", python_version())) return 0;
  if (!dict_steal(retval, "NumPy", numpy_version())) return 0;
  if (!dict_steal(retval, "xbob.blitz", xbob_blitz_version())) return 0;
  if (!dict_steal(retval, "Bob", bob_version())) return 0;

  Py_INCREF(retval);
  return retval;
}

static PyMethodDef module_methods[] = {
    {0}  /* Sentinel */
};

PyDoc_STRVAR(module_docstr,
"Information about software used to compile the C++ Bob API"
);

#if PY_VERSION_HEX >= 0x03000000
static PyModuleDef module_definition = {
  PyModuleDef_HEAD_INIT,
  XBOB_EXT_MODULE_NAME,
  module_docstr,
  -1,
  module_methods,
  0, 0, 0, 0
};
#endif

static PyObject* create_module (void) {

# if PY_VERSION_HEX >= 0x03000000
  PyObject* m = PyModule_Create(&module_definition);
# else
  PyObject* m = Py_InitModule3(XBOB_EXT_MODULE_NAME, module_methods, module_docstr);
# endif
  if (!m) return 0;
  auto m_ = make_safe(m); ///< protects against early returns

  /* register version numbers and constants */
  if (PyModule_AddStringConstant(m, "module", XBOB_EXT_MODULE_VERSION) < 0)
    return 0;

  if (PyModule_AddIntConstant(m, "api", XBOB_CORE_API_VERSION) < 0)
    return 0;

  PyObject* externals = build_version_dictionary();
  if (!externals) return 0;
  if (PyModule_AddObject(m, "externals", externals) < 0) return 0;

  if (import_xbob_blitz() < 0) return 0;

  Py_INCREF(m);
  return m;

}

PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) {
# if PY_VERSION_HEX >= 0x03000000
  return
# endif
    create_module();
}
<|endoftext|>