<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <fcntl.h>
#include <cerrno>
#include <unistd.h>

#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/file.h>

#include <vespa/defaults.h>
#include <vespa/log/llparser.h>
#include "llreader.h"
#include <vespa/log/log.h>
#include <chrono>

LOG_SETUP("runserver");

// XXX should close all file descriptors,
// XXX but that makes logging go haywire

static volatile sig_atomic_t gotstopsig = 0;
static volatile sig_atomic_t lastsig = 0;
static volatile sig_atomic_t unhandledsig = 0;

extern "C" {
void termsig(int sig) {
    lastsig = sig;
    gotstopsig = 1;
    unhandledsig = 1;
}
}

namespace {

using namespace std::chrono;

time_t steady_time() {
    return duration_cast<seconds>(steady_clock::now().time_since_epoch()).count();
}

}

class PidFile
{
private:
    char *_pidfile;
    int _fd;
    PidFile(const PidFile&);
    PidFile& operator= (const PidFile&);
public:
    PidFile(const char *pidfile) : _pidfile(strdup(pidfile)), _fd(-1) {}
    ~PidFile() { free(_pidfile); if (_fd >= 0) close(_fd); }
    int readPid();
    void writePid();
    bool writeOpen();
    bool anotherRunning();
    bool canStealLock();
    void cleanUp();
};

void
PidFile::cleanUp()
{
    if (!anotherRunning()) remove(_pidfile);
    if (_fd >= 0) close(_fd);
    _fd = -1;
}

bool
PidFile::writeOpen()
{
    if (_fd >= 0) close(_fd);
    int flags = O_CREAT | O_WRONLY | O_NONBLOCK;
    _fd = open(_pidfile, flags, 0644);
    if (_fd < 0) {
        fprintf(stderr, "could not create pidfile %s: %s\n", _pidfile,
                strerror(errno));
        return false;
    }
    if (flock(_fd, LOCK_EX | LOCK_NB) != 0) {
        fprintf(stderr, "could not lock pidfile %s: %s\n", _pidfile,
                strerror(errno));
        close(_fd);
        _fd = -1;
        return false;
    }
    fcntl(_fd, F_SETFD, FD_CLOEXEC);
    return true;
}

void
PidFile::writePid()
{
    if (_fd < 0) abort();
    int didtruncate = ftruncate(_fd, (off_t)0);
    if (didtruncate != 0) {
        fprintf(stderr, "could not truncate pid file %s: %s\n",
                _pidfile, strerror(errno));
        exit(1);
    }
    char buf[100];
    sprintf(buf, "%d\n", getpid());
    int l = strlen(buf);
    ssize_t didw = write(_fd, buf, l);
    if (didw != l) {
        fprintf(stderr, "could not write pid to %s: %s\n",
                _pidfile, strerror(errno));
        exit(1);
    }
    LOG(debug, "wrote '%s' to %s (fd %d)", buf, _pidfile, _fd);
}

int
PidFile::readPid()
{
    FILE *pf = fopen(_pidfile, "r");
    if (pf == NULL) return 0;
    char buf[100];
    strcpy(buf, "0");
    char *fgetsres = fgets(buf, 100, pf);
    fclose(pf);
    return ((fgetsres != nullptr) ? atoi(buf) : 0);
}

bool
PidFile::anotherRunning()
{
    int pid = readPid();
    if (pid < 1 || pid == getpid()) {
        // no valid pid, or my own pid
        return false;
    }
    if (canStealLock()) {
        return false;
    }
    return (kill(pid, 0) == 0 || errno == EPERM);
}

bool
PidFile::canStealLock()
{
    int flags = O_WRONLY | O_NONBLOCK;
    int desc = open(_pidfile, flags, 0644);
    if (desc < 0) {
        return false;
    }
    if (flock(desc, LOCK_EX | LOCK_NB) != 0) {
        close(desc);
        return false;
    }
    flock(desc, LOCK_UN | LOCK_NB);
    close(desc);
    return true;
}

using namespace ns_log;

int loop(const char *svc, char * const * run)
{
    int pstdout[2];
    int pstderr[2];

    if (pipe(pstdout) < 0 || pipe(pstderr) < 0) {
        LOG(error, "pipe: %s", strerror(errno));
        exit(1);
    }
    LOG(debug, "stdout pipe %d <- %d; stderr pipe %d <- %d",
        pstdout[0], pstdout[1],
        pstderr[0], pstderr[1]);

    int high = 1 + pstdout[0] + pstderr[0];

    pid_t child = fork();

    if (child == 0) {
        // I am the child process
        dup2(pstdout[1], 1);
        dup2(pstderr[1], 2);
        close(pstdout[0]);
        close(pstderr[0]);
        close(pstdout[1]);
        close(pstderr[1]);
        execvp(run[0], run);
        LOG(error, "exec %s: %s", run[0], strerror(errno));
        exit(1);
    }
    if (child < 0) {
        LOG(error, "fork(): %s", strerror(errno));
        exit(1);
    }
    // I am the parent process

    LOG(debug, "started %s (pid %d)", run[0], (int)child);
    std::string torun = run[0];
    for (char * const *arg = (run + 1); *arg != NULL; ++arg) {
        torun += " ";
        torun += *arg;
    }

    {
        torun += " (pid ";
        char buf[20];
        sprintf(buf, "%d", (int)child);
        torun += buf;
        torun += ")";
    }
    EV_STARTING(torun.c_str());

    close(pstdout[1]);
    close(pstderr[1]);

    LLParser outvia;
    LLParser errvia;
    outvia.setDefaultLevel(Logger::info);
    errvia.setDefaultLevel(Logger::warning);

    outvia.setService(svc);
    errvia.setService(svc);
    outvia.setComponent("stdout");
    errvia.setComponent("stderr");
    outvia.setPid(child);
    errvia.setPid(child);

    InputBuf outReader(pstdout[0]);
    InputBuf errReader(pstderr[0]);

    bool outeof = false;
    bool erreof = false;

    int wstat = 0;

    while (child || !outeof || !erreof) {
        struct timeval timeout;

        timeout.tv_sec = 0;
        timeout.tv_usec = 100000; // == 100 ms == 1/10 s

        fd_set pipes;

        FD_ZERO(&pipes);
        if (!outeof) FD_SET(pstdout[0], &pipes);
        if (!erreof) FD_SET(pstderr[0], &pipes);

        int n = select(high, &pipes, NULL, NULL, &timeout);
        if (n > 0) {
            if (FD_ISSET(pstdout[0], &pipes)) {
                LOG(debug, "out reader has input");
                if (outReader.blockRead()) {
                    while (outReader.hasInput()) {
                        LOG(debug, "process out reader input");
                        outReader.doInput(outvia);
                    }
                } else {
                    LOG(debug, "eof on stdout");
                    outeof = true; // EOF on stdout
                    close(pstdout[0]);
                }
            }
            if (FD_ISSET(pstderr[0], &pipes)) {
                LOG(debug, "err reader has input");
                if (errReader.blockRead()) {
                    while (errReader.hasInput()) {
                        LOG(debug, "process err reader input");
                        errReader.doInput(errvia);
                    }
                } else {
                    LOG(debug, "eof on stderr");
                    erreof = true; // EOF on stderr
                    close(pstderr[0]);
                }
            }
        }

        if (child != 0) {
            int cpid = waitpid(child, &wstat, WNOHANG);
            if (cpid == child) {
                if (WIFSTOPPED(wstat)) {
                    LOG(info, "child %d stopped, waiting for it to continue",
                        cpid);
                } else if (WIFEXITED(wstat)) {
                    // child terminated
                    LOG(debug, "child %d exit status: %d", cpid,
                        (int)WEXITSTATUS(wstat));
                    EV_STOPPED(torun.c_str(), (int)child, (int)WEXITSTATUS(wstat));
                    child = 0;
                } else if (WIFSIGNALED(wstat)) {
                    if (WTERMSIG(wstat) != lastsig) {
                        LOG(warning, "child died from signal: %d", WTERMSIG(wstat));
                        if (WCOREDUMP(wstat)) {
                            LOG(info, "child %d dumped core", cpid);
                        }
                    }
                    child = 0;
                } else {
                    LOG(error, "unexpected status %d from waidpit", wstat);
                    abort();
                }
            } else if (cpid < 0) {
                LOG(error, "waitpid: %s", strerror(errno));
                abort();
            } else if (cpid != 0) {
                LOG(warning, "unexpected status %d for pid %d",
                    wstat, cpid);
                abort();
            }
        }
        if (unhandledsig && child != 0) {
            LOG(debug, "got signal %d, sending to pid %d",
                (int)lastsig, (int)child);
            char why[256];
            sprintf(why, "got signal %d", (int)lastsig);
            EV_STOPPING(torun.c_str(), why);
            kill(child, lastsig);
            unhandledsig = 0;
        }
    }
    if (WIFSIGNALED(wstat))
        return WTERMSIG(wstat);
    return WEXITSTATUS(wstat);
}

void usage(char *prog, int es)
{
    fprintf(stderr, "Usage: %s\n"
            "       [-s service] [-r restartinterval] [-p pidfile]"
            " program [args ...]\n"
            "or:    [-p pidfile] [-k killcmd] -S\n", prog);
    exit(es);
}

int main(int argc, char *argv[])
{
    bool doStop = false;
    int restart = 0;
    const char *service = "runserver";
    const char *pidfile = "vespa-runserver.pid"; // XXX bad default?
    const char *killcmd = NULL;

    signal(SIGQUIT, SIG_IGN);

    int ch;
    while ((ch = getopt(argc, argv, "k:s:r:p:Sh")) != -1) {
        switch (ch) {
        case 's':
            service = optarg;
            break;
        case 'r':
            restart = atoi(optarg);
            break;
        case 'p':
            pidfile = optarg;
            break;
        case 'S':
            doStop = true;
            break;
        case 'k':
            killcmd = optarg;
            break;
        default:
            usage(argv[0], ch != 'h');
        }
    }

    const char *envROOT = getenv("ROOT");
    if (envROOT == NULL || envROOT[0] == '\0') {
        envROOT = vespa::Defaults::vespaHome();
        setenv("ROOT", envROOT, 1);
    }
    if (chdir(envROOT) != 0) {
        fprintf(stderr, "Cannot chdir to %s: %s\n", envROOT, strerror(errno));
        exit(1);
    }

    PidFile mypf(pidfile);
    if (doStop) {
        if (mypf.anotherRunning()) {
            int pid = mypf.readPid();
            if (killcmd != NULL) {
                fprintf(stdout, "%s was running with pid %d, running '%s' to stop it\n",
                        service, pid, killcmd);
                if (system(killcmd) != 0) {
                    fprintf(stderr, "WARNING: stop command '%s' had some problem\n", killcmd);
                }
            } else {
                fprintf(stdout, "%s was running with pid %d, sending SIGTERM\n",
                    service, pid);
                if (killpg(pid, SIGTERM) != 0) {
                    fprintf(stderr, "could not signal %d: %s\n", pid,
                            strerror(errno));
                    exit(1);
                }
            }
            fprintf(stdout, "Waiting for exit (up to 60 seconds)\n");
            for (int cnt(0); cnt < 1800; cnt++) {
                usleep(100000); // wait 0.1 seconds
                if ((cnt > 300) && (cnt % 100 == 0)) {
                    killpg(pid, SIGTERM);
                }
                if (killpg(pid, 0) == 0) {
                    if (cnt%10 == 0) {
                        fprintf(stdout, ".");
                        fflush(stdout);
                    }
                } else {
                    fprintf(stdout, "DONE\n");
                    break;
                }
                if (cnt == 900) {
                    printf("\ngiving up, sending KILL signal\n");
                    killpg(pid, SIGKILL);
                }
            }
        } else {
            fprintf(stdout, "%s not running according to %s\n",
                    service, pidfile);
        }
        mypf.cleanUp();
        exit(0);
    }
    if (optind >= argc || killcmd != NULL) {
        usage(argv[0], 1);
    }

    if (mypf.anotherRunning()) {
        fprintf(stderr, "runserver already running with pid %d\n",
                mypf.readPid());
        exit(0);
    }

    if (!mypf.writeOpen()) {
        perror(pidfile);
        return 1;
    }

    pid_t rsp = fork();
    if (rsp == 0) {
        close(0);
        if (open("/dev/null", O_RDONLY) != 0) {
            perror("open /dev/null for reading failed");
            exit(1);
        }
        close(1);
        if (open("/dev/null", O_WRONLY) != 1) {
            perror("open /dev/null for writing failed");
            exit(1);
        }
        dup2(1, 2);
        if (setsid() < 0) {
            perror("setsid");
            exit(1);
        }
        struct sigaction act;
        struct sigaction oact;

        memset(&act, 0, sizeof(act));

        act.sa_handler = termsig;

        sigaction(SIGINT, &act, &oact);
        sigaction(SIGTERM, &act, &oact);

        int stat = 0;
        try {
            mypf.writePid();
            do {
                time_t laststart = steady_time();
                stat = loop(service, argv+optind);
                if (restart > 0 && !gotstopsig) {
                    int wt = restart + laststart - steady_time();
                    if (wt < 0) wt = 0;
                    LOG(info, "will restart in %d seconds", wt);
                }
                while (!gotstopsig && steady_time() - laststart < restart) {
                    sleep(1);
                }
            } while (!gotstopsig && restart > 0);
        } catch (MsgException& ex) {
            LOG(error, "exception: '%s'", ex.what());
            exit(1);
        }
        if (restart > 0) {
            LOG(debug, "final exit status: %d", stat);
        }
        mypf.cleanUp();
        exit(stat);
    }

    if (rsp < 0) {
        perror("fork");
        return 1;
    }
    printf("runserver(%s) running with pid: %d\n", service, rsp);
    return 0;
}
<commit_msg>Add include of header file for signal handling.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <fcntl.h>
#include <cerrno>
#include <unistd.h>
#include <csignal>

#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/file.h>

#include <vespa/defaults.h>
#include <vespa/log/llparser.h>
#include "llreader.h"
#include <vespa/log/log.h>
#include <chrono>

LOG_SETUP("runserver");

// XXX should close all file descriptors,
// XXX but that makes logging go haywire

static volatile sig_atomic_t gotstopsig = 0;
static volatile sig_atomic_t lastsig = 0;
static volatile sig_atomic_t unhandledsig = 0;

extern "C" {
void termsig(int sig) {
    lastsig = sig;
    gotstopsig = 1;
    unhandledsig = 1;
}
}

namespace {

using namespace std::chrono;

time_t steady_time() {
    return duration_cast<seconds>(steady_clock::now().time_since_epoch()).count();
}

}

class PidFile
{
private:
    char *_pidfile;
    int _fd;
    PidFile(const PidFile&);
    PidFile& operator= (const PidFile&);
public:
    PidFile(const char *pidfile) : _pidfile(strdup(pidfile)), _fd(-1) {}
    ~PidFile() { free(_pidfile); if (_fd >= 0) close(_fd); }
    int readPid();
    void writePid();
    bool writeOpen();
    bool anotherRunning();
    bool canStealLock();
    void cleanUp();
};

void
PidFile::cleanUp()
{
    if (!anotherRunning()) remove(_pidfile);
    if (_fd >= 0) close(_fd);
    _fd = -1;
}

bool
PidFile::writeOpen()
{
    if (_fd >= 0) close(_fd);
    int flags = O_CREAT | O_WRONLY | O_NONBLOCK;
    _fd = open(_pidfile, flags, 0644);
    if (_fd < 0) {
        fprintf(stderr, "could not create pidfile %s: %s\n", _pidfile,
                strerror(errno));
        return false;
    }
    if (flock(_fd, LOCK_EX | LOCK_NB) != 0) {
        fprintf(stderr, "could not lock pidfile %s: %s\n", _pidfile,
                strerror(errno));
        close(_fd);
        _fd = -1;
        return false;
    }
    fcntl(_fd, F_SETFD, FD_CLOEXEC);
    return true;
}

void
PidFile::writePid()
{
    if (_fd < 0) abort();
    int didtruncate = ftruncate(_fd, (off_t)0);
    if (didtruncate != 0) {
        fprintf(stderr, "could not truncate pid file %s: %s\n",
                _pidfile, strerror(errno));
        exit(1);
    }
    char buf[100];
    sprintf(buf, "%d\n", getpid());
    int l = strlen(buf);
    ssize_t didw = write(_fd, buf, l);
    if (didw != l) {
        fprintf(stderr, "could not write pid to %s: %s\n",
                _pidfile, strerror(errno));
        exit(1);
    }
    LOG(debug, "wrote '%s' to %s (fd %d)", buf, _pidfile, _fd);
}

int
PidFile::readPid()
{
    FILE *pf = fopen(_pidfile, "r");
    if (pf == NULL) return 0;
    char buf[100];
    strcpy(buf, "0");
    char *fgetsres = fgets(buf, 100, pf);
    fclose(pf);
    return ((fgetsres != nullptr) ? atoi(buf) : 0);
}

bool
PidFile::anotherRunning()
{
    int pid = readPid();
    if (pid < 1 || pid == getpid()) {
        // no valid pid, or my own pid
        return false;
    }
    if (canStealLock()) {
        return false;
    }
    return (kill(pid, 0) == 0 || errno == EPERM);
}

bool
PidFile::canStealLock()
{
    int flags = O_WRONLY | O_NONBLOCK;
    int desc = open(_pidfile, flags, 0644);
    if (desc < 0) {
        return false;
    }
    if (flock(desc, LOCK_EX | LOCK_NB) != 0) {
        close(desc);
        return false;
    }
    flock(desc, LOCK_UN | LOCK_NB);
    close(desc);
    return true;
}

using namespace ns_log;

int loop(const char *svc, char * const * run)
{
    int pstdout[2];
    int pstderr[2];

    if (pipe(pstdout) < 0 || pipe(pstderr) < 0) {
        LOG(error, "pipe: %s", strerror(errno));
        exit(1);
    }
    LOG(debug, "stdout pipe %d <- %d; stderr pipe %d <- %d",
        pstdout[0], pstdout[1],
        pstderr[0], pstderr[1]);

    int high = 1 + pstdout[0] + pstderr[0];

    pid_t child = fork();

    if (child == 0) {
        // I am the child process
        dup2(pstdout[1], 1);
        dup2(pstderr[1], 2);
        close(pstdout[0]);
        close(pstderr[0]);
        close(pstdout[1]);
        close(pstderr[1]);
        execvp(run[0], run);
        LOG(error, "exec %s: %s", run[0], strerror(errno));
        exit(1);
    }
    if (child < 0) {
        LOG(error, "fork(): %s", strerror(errno));
        exit(1);
    }
    // I am the parent process

    LOG(debug, "started %s (pid %d)", run[0], (int)child);
    std::string torun = run[0];
    for (char * const *arg = (run + 1); *arg != NULL; ++arg) {
        torun += " ";
        torun += *arg;
    }

    {
        torun += " (pid ";
        char buf[20];
        sprintf(buf, "%d", (int)child);
        torun += buf;
        torun += ")";
    }
    EV_STARTING(torun.c_str());

    close(pstdout[1]);
    close(pstderr[1]);

    LLParser outvia;
    LLParser errvia;
    outvia.setDefaultLevel(Logger::info);
    errvia.setDefaultLevel(Logger::warning);

    outvia.setService(svc);
    errvia.setService(svc);
    outvia.setComponent("stdout");
    errvia.setComponent("stderr");
    outvia.setPid(child);
    errvia.setPid(child);

    InputBuf outReader(pstdout[0]);
    InputBuf errReader(pstderr[0]);

    bool outeof = false;
    bool erreof = false;

    int wstat = 0;

    while (child || !outeof || !erreof) {
        struct timeval timeout;

        timeout.tv_sec = 0;
        timeout.tv_usec = 100000; // == 100 ms == 1/10 s

        fd_set pipes;

        FD_ZERO(&pipes);
        if (!outeof) FD_SET(pstdout[0], &pipes);
        if (!erreof) FD_SET(pstderr[0], &pipes);

        int n = select(high, &pipes, NULL, NULL, &timeout);
        if (n > 0) {
            if (FD_ISSET(pstdout[0], &pipes)) {
                LOG(debug, "out reader has input");
                if (outReader.blockRead()) {
                    while (outReader.hasInput()) {
                        LOG(debug, "process out reader input");
                        outReader.doInput(outvia);
                    }
                } else {
                    LOG(debug, "eof on stdout");
                    outeof = true; // EOF on stdout
                    close(pstdout[0]);
                }
            }
            if (FD_ISSET(pstderr[0], &pipes)) {
                LOG(debug, "err reader has input");
                if (errReader.blockRead()) {
                    while (errReader.hasInput()) {
                        LOG(debug, "process err reader input");
                        errReader.doInput(errvia);
                    }
                } else {
                    LOG(debug, "eof on stderr");
                    erreof = true; // EOF on stderr
                    close(pstderr[0]);
                }
            }
        }

        if (child != 0) {
            int cpid = waitpid(child, &wstat, WNOHANG);
            if (cpid == child) {
                if (WIFSTOPPED(wstat)) {
                    LOG(info, "child %d stopped, waiting for it to continue",
                        cpid);
                } else if (WIFEXITED(wstat)) {
                    // child terminated
                    LOG(debug, "child %d exit status: %d", cpid,
                        (int)WEXITSTATUS(wstat));
                    EV_STOPPED(torun.c_str(), (int)child, (int)WEXITSTATUS(wstat));
                    child = 0;
                } else if (WIFSIGNALED(wstat)) {
                    if (WTERMSIG(wstat) != lastsig) {
                        LOG(warning, "child died from signal: %d", WTERMSIG(wstat));
                        if (WCOREDUMP(wstat)) {
                            LOG(info, "child %d dumped core", cpid);
                        }
                    }
                    child = 0;
                } else {
                    LOG(error, "unexpected status %d from waidpit", wstat);
                    abort();
                }
            } else if (cpid < 0) {
                LOG(error, "waitpid: %s", strerror(errno));
                abort();
            } else if (cpid != 0) {
                LOG(warning, "unexpected status %d for pid %d",
                    wstat, cpid);
                abort();
            }
        }
        if (unhandledsig && child != 0) {
            LOG(debug, "got signal %d, sending to pid %d",
                (int)lastsig, (int)child);
            char why[256];
            sprintf(why, "got signal %d", (int)lastsig);
            EV_STOPPING(torun.c_str(), why);
            kill(child, lastsig);
            unhandledsig = 0;
        }
    }
    if (WIFSIGNALED(wstat))
        return WTERMSIG(wstat);
    return WEXITSTATUS(wstat);
}

void usage(char *prog, int es)
{
    fprintf(stderr, "Usage: %s\n"
            "       [-s service] [-r restartinterval] [-p pidfile]"
            " program [args ...]\n"
            "or:    [-p pidfile] [-k killcmd] -S\n", prog);
    exit(es);
}

int main(int argc, char *argv[])
{
    bool doStop = false;
    int restart = 0;
    const char *service = "runserver";
    const char *pidfile = "vespa-runserver.pid"; // XXX bad default?
    const char *killcmd = NULL;

    signal(SIGQUIT, SIG_IGN);

    int ch;
    while ((ch = getopt(argc, argv, "k:s:r:p:Sh")) != -1) {
        switch (ch) {
        case 's':
            service = optarg;
            break;
        case 'r':
            restart = atoi(optarg);
            break;
        case 'p':
            pidfile = optarg;
            break;
        case 'S':
            doStop = true;
            break;
        case 'k':
            killcmd = optarg;
            break;
        default:
            usage(argv[0], ch != 'h');
        }
    }

    const char *envROOT = getenv("ROOT");
    if (envROOT == NULL || envROOT[0] == '\0') {
        envROOT = vespa::Defaults::vespaHome();
        setenv("ROOT", envROOT, 1);
    }
    if (chdir(envROOT) != 0) {
        fprintf(stderr, "Cannot chdir to %s: %s\n", envROOT, strerror(errno));
        exit(1);
    }

    PidFile mypf(pidfile);
    if (doStop) {
        if (mypf.anotherRunning()) {
            int pid = mypf.readPid();
            if (killcmd != NULL) {
                fprintf(stdout, "%s was running with pid %d, running '%s' to stop it\n",
                        service, pid, killcmd);
                if (system(killcmd) != 0) {
                    fprintf(stderr, "WARNING: stop command '%s' had some problem\n", killcmd);
                }
            } else {
                fprintf(stdout, "%s was running with pid %d, sending SIGTERM\n",
                    service, pid);
                if (killpg(pid, SIGTERM) != 0) {
                    fprintf(stderr, "could not signal %d: %s\n", pid,
                            strerror(errno));
                    exit(1);
                }
            }
            fprintf(stdout, "Waiting for exit (up to 60 seconds)\n");
            for (int cnt(0); cnt < 1800; cnt++) {
                usleep(100000); // wait 0.1 seconds
                if ((cnt > 300) && (cnt % 100 == 0)) {
                    killpg(pid, SIGTERM);
                }
                if (killpg(pid, 0) == 0) {
                    if (cnt%10 == 0) {
                        fprintf(stdout, ".");
                        fflush(stdout);
                    }
                } else {
                    fprintf(stdout, "DONE\n");
                    break;
                }
                if (cnt == 900) {
                    printf("\ngiving up, sending KILL signal\n");
                    killpg(pid, SIGKILL);
                }
            }
        } else {
            fprintf(stdout, "%s not running according to %s\n",
                    service, pidfile);
        }
        mypf.cleanUp();
        exit(0);
    }
    if (optind >= argc || killcmd != NULL) {
        usage(argv[0], 1);
    }

    if (mypf.anotherRunning()) {
        fprintf(stderr, "runserver already running with pid %d\n",
                mypf.readPid());
        exit(0);
    }

    if (!mypf.writeOpen()) {
        perror(pidfile);
        return 1;
    }

    pid_t rsp = fork();
    if (rsp == 0) {
        close(0);
        if (open("/dev/null", O_RDONLY) != 0) {
            perror("open /dev/null for reading failed");
            exit(1);
        }
        close(1);
        if (open("/dev/null", O_WRONLY) != 1) {
            perror("open /dev/null for writing failed");
            exit(1);
        }
        dup2(1, 2);
        if (setsid() < 0) {
            perror("setsid");
            exit(1);
        }
        struct sigaction act;
        struct sigaction oact;

        memset(&act, 0, sizeof(act));

        act.sa_handler = termsig;

        sigaction(SIGINT, &act, &oact);
        sigaction(SIGTERM, &act, &oact);

        int stat = 0;
        try {
            mypf.writePid();
            do {
                time_t laststart = steady_time();
                stat = loop(service, argv+optind);
                if (restart > 0 && !gotstopsig) {
                    int wt = restart + laststart - steady_time();
                    if (wt < 0) wt = 0;
                    LOG(info, "will restart in %d seconds", wt);
                }
                while (!gotstopsig && steady_time() - laststart < restart) {
                    sleep(1);
                }
            } while (!gotstopsig && restart > 0);
        } catch (MsgException& ex) {
            LOG(error, "exception: '%s'", ex.what());
            exit(1);
        }
        if (restart > 0) {
            LOG(debug, "final exit status: %d", stat);
        }
        mypf.cleanUp();
        exit(stat);
    }

    if (rsp < 0) {
        perror("fork");
        return 1;
    }
    printf("runserver(%s) running with pid: %d\n", service, rsp);
    return 0;
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EthashGPUMiner.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 *
 * Determines the PoW algorithm.
 */

#if ETH_ETHASHCL || !ETH_TRUE

#include "EthashGPUMiner.h"
#include <thread>
#include <chrono>
#include <libethash-cl/ethash_cl_miner.h>
using namespace std;
using namespace dev;
using namespace eth;

namespace dev
{
namespace eth
{

class EthashCLHook: public ethash_cl_miner::search_hook
{
public:
	EthashCLHook(EthashGPUMiner* _owner): m_owner(_owner) {}
	EthashCLHook(EthashCLHook const&) = delete;

	void abort()
	{
		{
			UniqueGuard l(x_all);
			if (m_aborted)
				return;
//		cdebug << "Attempting to abort";

			m_abort = true;
		}
		// m_abort is true so now searched()/found() will return true to abort the search.
		// we hang around on this thread waiting for them to point out that they have aborted since
		// otherwise we may end up deleting this object prior to searched()/found() being called.
		m_aborted.wait(true);
//		for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
//			std::this_thread::sleep_for(chrono::milliseconds(30));
//		if (!m_aborted)
//			cwarn << "Couldn't abort. Abandoning OpenCL process.";
	}

	void reset()
	{
		UniqueGuard l(x_all);
		m_aborted = m_abort = false;
	}

protected:
	virtual bool found(uint64_t const* _nonces, uint32_t _count) override
	{
//		dev::operator <<(std::cerr << "Found nonces: ", vector<uint64_t>(_nonces, _nonces + _count)) << std::endl;
		for (uint32_t i = 0; i < _count; ++i)
			if (m_owner->report(_nonces[i]))
				return (m_aborted = true);
		return m_owner->shouldStop();
	}

	virtual bool searched(uint64_t _startNonce, uint32_t _count) override
	{
		UniqueGuard l(x_all);
//		std::cerr << "Searched " << _count << " from " << _startNonce << std::endl;
		m_owner->accumulateHashes(_count);
		m_last = _startNonce + _count;
		if (m_abort || m_owner->shouldStop())
			return (m_aborted = true);
		return false;
	}

private:
	Mutex x_all;
	uint64_t m_last;
	bool m_abort = false;
	Notified<bool> m_aborted = {true};
	EthashGPUMiner* m_owner = nullptr;
};

}
}

unsigned EthashGPUMiner::s_platformId = 0;
unsigned EthashGPUMiner::s_deviceId = 0;
unsigned EthashGPUMiner::s_numInstances = 0;

EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci):
	GenericMiner<EthashProofOfWork>(_ci),
	Worker("gpuminer" + toString(index())),
	m_hook(new EthashCLHook(this))
{
}

EthashGPUMiner::~EthashGPUMiner()
{
	pause();
	delete m_miner;
	delete m_hook;
}

bool EthashGPUMiner::report(uint64_t _nonce)
{
	Nonce n = (Nonce)(u64)_nonce;
	EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
	if (r.value < work().boundary)
		return submitProof(Solution{n, r.mixHash});
	return false;
}

void EthashGPUMiner::kickOff()
{
	m_hook->reset();
	startWorking();
}

void EthashGPUMiner::workLoop()
{
	// take local copy of work since it may end up being overwritten by kickOff/pause.
	try {
		WorkPackage w = work();
		cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash;
		if (!m_miner || m_minerSeed != w.seedHash)
		{
			cnote << "Initialising miner...";
			m_minerSeed = w.seedHash;

			delete m_miner;
			m_miner = new ethash_cl_miner;

			unsigned device = instances() > 1 ? index() : s_deviceId;

			EthashAux::FullType dag;
			while (true)
			{
				if ((dag = EthashAux::full(w.seedHash, true)))
					break;
				if (shouldStop())
				{
					delete m_miner;
					m_miner = nullptr;
					return;
				}
				cnote << "Awaiting DAG";
				this_thread::sleep_for(chrono::milliseconds(500));
			}
			bytesConstRef dagData = dag->data();
			m_miner->init(dagData.data(), dagData.size(), s_platformId, device);
		}

		uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
		m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook);
	}
	catch (cl::Error const& _e)
	{
		delete m_miner;
		m_miner = nullptr;
		cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")";
	}
}

void EthashGPUMiner::pause()
{
	m_hook->abort();
	stopWorking();
}

std::string EthashGPUMiner::platformInfo()
{
	return ethash_cl_miner::platform_info(s_platformId, s_deviceId);
}

unsigned EthashGPUMiner::getNumDevices()
{
	return ethash_cl_miner::getNumDevices(s_platformId);
}

void EthashGPUMiner::listDevices()
{
	return ethash_cl_miner::listDevices();
}

bool EthashGPUMiner::configureGPU(
	unsigned _localWorkSize,
	unsigned _globalWorkSizeMultiplier,
	unsigned _msPerBatch,
	unsigned _platformId,
	unsigned _deviceId,
	bool _allowCPU,
	unsigned _extraGPUMemory,
	uint64_t _currentBlock
)
{
	s_platformId = _platformId;
	s_deviceId = _deviceId;

	if (_localWorkSize != 32 && _localWorkSize != 64 && _localWorkSize != 128 && _localWorkSize != 256)
	{
		cout << "Given localWorkSize of " << toString(_localWorkSize) << "is invalid. Must be either 32,64, or 128" << endl;
		return false;
	}

	if (!ethash_cl_miner::configureGPU(
			_platformId,
			_localWorkSize,
			_globalWorkSizeMultiplier * _localWorkSize,
			_msPerBatch,
			_allowCPU,
			_extraGPUMemory,
			_currentBlock)
	)
	{
		cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl;
		return false;
	}
	return true;
}

#endif
<commit_msg>Update EthashGPUMiner.cpp<commit_after>/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EthashGPUMiner.cpp
 * @author Gav Wood <i@gavwood.com>
 * @date 2014
 *
 * Determines the PoW algorithm.
 */

#if ETH_ETHASHCL || !ETH_TRUE

#include "EthashGPUMiner.h"
#include <thread>
#include <chrono>
#include <libethash-cl/ethash_cl_miner.h>
using namespace std;
using namespace dev;
using namespace eth;

namespace dev
{
namespace eth
{

class EthashCLHook: public ethash_cl_miner::search_hook
{
public:
	EthashCLHook(EthashGPUMiner* _owner): m_owner(_owner) {}
	EthashCLHook(EthashCLHook const&) = delete;

	void abort()
	{
		{
			UniqueGuard l(x_all);
			if (m_aborted)
				return;
//		cdebug << "Attempting to abort";

			m_abort = true;
		}
		// m_abort is true so now searched()/found() will return true to abort the search.
		// we hang around on this thread waiting for them to point out that they have aborted since
		// otherwise we may end up deleting this object prior to searched()/found() being called.
		m_aborted.wait(true);
//		for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout)
//			std::this_thread::sleep_for(chrono::milliseconds(30));
//		if (!m_aborted)
//			cwarn << "Couldn't abort. Abandoning OpenCL process.";
	}

	void reset()
	{
		UniqueGuard l(x_all);
		m_aborted = m_abort = false;
	}

protected:
	virtual bool found(uint64_t const* _nonces, uint32_t _count) override
	{
//		dev::operator <<(std::cerr << "Found nonces: ", vector<uint64_t>(_nonces, _nonces + _count)) << std::endl;
		for (uint32_t i = 0; i < _count; ++i)
			if (m_owner->report(_nonces[i]))
				return (m_aborted = true);
		return m_owner->shouldStop();
	}

	virtual bool searched(uint64_t _startNonce, uint32_t _count) override
	{
		UniqueGuard l(x_all);
//		std::cerr << "Searched " << _count << " from " << _startNonce << std::endl;
		m_owner->accumulateHashes(_count);
		m_last = _startNonce + _count;
		if (m_abort || m_owner->shouldStop())
			return (m_aborted = true);
		return false;
	}

private:
	Mutex x_all;
	uint64_t m_last;
	bool m_abort = false;
	Notified<bool> m_aborted = {true};
	EthashGPUMiner* m_owner = nullptr;
};

}
}

unsigned EthashGPUMiner::s_platformId = 0;
unsigned EthashGPUMiner::s_deviceId = 0;
unsigned EthashGPUMiner::s_numInstances = 0;

EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci):
	GenericMiner<EthashProofOfWork>(_ci),
	Worker("gpuminer" + toString(index())),
	m_hook(new EthashCLHook(this))
{
}

EthashGPUMiner::~EthashGPUMiner()
{
	pause();
	delete m_miner;
	delete m_hook;
}

bool EthashGPUMiner::report(uint64_t _nonce)
{
	Nonce n = (Nonce)(u64)_nonce;
	EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
	if (r.value < work().boundary)
		return submitProof(Solution{n, r.mixHash});
	return false;
}

void EthashGPUMiner::kickOff()
{
	m_hook->reset();
	startWorking();
}

void EthashGPUMiner::workLoop()
{
	// take local copy of work since it may end up being overwritten by kickOff/pause.
	try {
		WorkPackage w = work();
		cnote << "workLoop" << !!m_miner << m_minerSeed << w.seedHash;
		if (!m_miner || m_minerSeed != w.seedHash)
		{
			cnote << "Initialising miner...";
			m_minerSeed = w.seedHash;

			delete m_miner;
			m_miner = new ethash_cl_miner;

			unsigned device = instances() > 1 ? index() : s_deviceId;

			EthashAux::FullType dag;
			while (true)
			{
				if ((dag = EthashAux::full(w.seedHash, true)))
					break;
				if (shouldStop())
				{
					delete m_miner;
					m_miner = nullptr;
					return;
				}
				cnote << "Awaiting DAG";
				this_thread::sleep_for(chrono::milliseconds(500));
			}
			bytesConstRef dagData = dag->data();
			m_miner->init(dagData.data(), dagData.size(), s_platformId, device);
		}

		uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192);
		m_miner->search(w.headerHash.data(), upper64OfBoundary, *m_hook);
	}
	catch (cl::Error const& _e)
	{
		delete m_miner;
		m_miner = nullptr;
		cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")";
	}
}

void EthashGPUMiner::pause()
{
	m_hook->abort();
	stopWorking();
}

std::string EthashGPUMiner::platformInfo()
{
	return ethash_cl_miner::platform_info(s_platformId, s_deviceId);
}

unsigned EthashGPUMiner::getNumDevices()
{
	return ethash_cl_miner::getNumDevices(s_platformId);
}

void EthashGPUMiner::listDevices()
{
	return ethash_cl_miner::listDevices();
}

bool EthashGPUMiner::configureGPU(
	unsigned _localWorkSize,
	unsigned _globalWorkSizeMultiplier,
	unsigned _msPerBatch,
	unsigned _platformId,
	unsigned _deviceId,
	bool _allowCPU,
	unsigned _extraGPUMemory,
	uint64_t _currentBlock
)
{
	s_platformId = _platformId;
	s_deviceId = _deviceId;

	if (_localWorkSize != 32 && _localWorkSize != 64 && _localWorkSize != 128 && _localWorkSize != 256)
	{
		cout << "Given localWorkSize of " << toString(_localWorkSize) << "is invalid. Must be either 32,64,128 or 256" << endl;
		return false;
	}

	if (!ethash_cl_miner::configureGPU(
			_platformId,
			_localWorkSize,
			_globalWorkSizeMultiplier * _localWorkSize,
			_msPerBatch,
			_allowCPU,
			_extraGPUMemory,
			_currentBlock)
	)
	{
		cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl;
		return false;
	}
	return true;
}

#endif
<|endoftext|>


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

#include "webkit/glue/webpreferences.h"

#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "third_party/WebKit/WebKit/chromium/public/WebRuntimeFeatures.h"
#include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSettings.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
#include "webkit/glue/webkit_glue.h"

using WebKit::WebRuntimeFeatures;
using WebKit::WebSettings;
using WebKit::WebString;
using WebKit::WebURL;
using WebKit::WebView;

void WebPreferences::Apply(WebView* web_view) const {
  WebSettings* settings = web_view->settings();
  settings->setStandardFontFamily(WideToUTF16Hack(standard_font_family));
  settings->setFixedFontFamily(WideToUTF16Hack(fixed_font_family));
  settings->setSerifFontFamily(WideToUTF16Hack(serif_font_family));
  settings->setSansSerifFontFamily(WideToUTF16Hack(sans_serif_font_family));
  settings->setCursiveFontFamily(WideToUTF16Hack(cursive_font_family));
  settings->setFantasyFontFamily(WideToUTF16Hack(fantasy_font_family));
  settings->setDefaultFontSize(default_font_size);
  settings->setDefaultFixedFontSize(default_fixed_font_size);
  settings->setMinimumFontSize(minimum_font_size);
  settings->setMinimumLogicalFontSize(minimum_logical_font_size);
  settings->setDefaultTextEncodingName(ASCIIToUTF16(default_encoding));
  settings->setJavaScriptEnabled(javascript_enabled);
  settings->setWebSecurityEnabled(web_security_enabled);
  settings->setJavaScriptCanOpenWindowsAutomatically(
      javascript_can_open_windows_automatically);
  settings->setLoadsImagesAutomatically(loads_images_automatically);
  settings->setPluginsEnabled(plugins_enabled);
  settings->setDOMPasteAllowed(dom_paste_enabled);
  settings->setDeveloperExtrasEnabled(developer_extras_enabled);
  settings->setNeedsSiteSpecificQuirks(site_specific_quirks_enabled);
  settings->setShrinksStandaloneImagesToFit(shrinks_standalone_images_to_fit);
  settings->setUsesEncodingDetector(uses_universal_detector);
  settings->setTextAreasAreResizable(text_areas_are_resizable);
  settings->setAllowScriptsToCloseWindows(allow_scripts_to_close_windows);
  if (user_style_sheet_enabled)
    settings->setUserStyleSheetLocation(user_style_sheet_location);
  else
    settings->setUserStyleSheetLocation(WebURL());
  settings->setAuthorAndUserStylesEnabled(author_and_user_styles_enabled);
  settings->setUsesPageCache(uses_page_cache);
  settings->setDownloadableBinaryFontsEnabled(remote_fonts_enabled);
  settings->setJavaScriptCanAccessClipboard(javascript_can_access_clipboard);
  settings->setXSSAuditorEnabled(xss_auditor_enabled);
  settings->setLocalStorageEnabled(local_storage_enabled);
  WebRuntimeFeatures::enableDatabase(
      WebRuntimeFeatures::isDatabaseEnabled() || databases_enabled);
  settings->setOfflineWebApplicationCacheEnabled(application_cache_enabled);
  settings->setHTML5ParserEnabled(enable_html5_parser);

  // This setting affects the behavior of links in an editable region:
  // clicking the link should select it rather than navigate to it.
  // Safari uses the same default. It is unlikley an embedder would want to
  // change this, since it would break existing rich text editors.
  settings->setEditableLinkBehaviorNeverLive();

  settings->setFontRenderingModeNormal();
  settings->setJavaEnabled(java_enabled);

  // Turn this on to cause WebCore to paint the resize corner for us.
  settings->setShouldPaintCustomScrollbars(true);

  // By default, allow_universal_access_from_file_urls is set to false and thus
  // we mitigate attacks from local HTML files by not granting file:// URLs
  // universal access. Only test shell will enable this.
  settings->setAllowUniversalAccessFromFileURLs(
      allow_universal_access_from_file_urls);
  settings->setAllowFileAccessFromFileURLs(allow_file_access_from_file_urls);

  // We prevent WebKit from checking if it needs to add a "text direction"
  // submenu to a context menu. it is not only because we don't need the result
  // but also because it cause a possible crash in Editor::hasBidiSelection().
  settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();

  // Enable experimental WebGL support if requested on command line
  // and support is compiled in.
  settings->setExperimentalWebGLEnabled(experimental_webgl_enabled);

  // Display colored borders around composited render layers if requested
  // on command line.
  settings->setShowDebugBorders(show_composited_layer_borders);

  // Enable gpu-accelerated compositing if requested on the command line.
  settings->setAcceleratedCompositingEnabled(accelerated_compositing_enabled);

  // Enable gpu-accelerated 2d canvas if requested on the command line.
  settings->setAccelerated2dCanvasEnabled(accelerated_2d_canvas_enabled);

  // Enable memory info reporting to page if requested on the command line.
  settings->setMemoryInfoEnabled(memory_info_enabled);

  for (WebInspectorPreferences::const_iterator it = inspector_settings.begin();
       it != inspector_settings.end(); ++it)
    web_view->setInspectorSetting(WebString::fromUTF8(it->first),
                                  WebString::fromUTF8(it->second));

  // Tabs to link is not part of the settings. WebCore calls
  // ChromeClient::tabsToLinks which is part of the glue code.
  web_view->setTabsToLinks(tabs_to_links);
}
<commit_msg>WebGL web preferences do not disable WebGL if already enabled.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/glue/webpreferences.h"

#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "third_party/WebKit/WebKit/chromium/public/WebRuntimeFeatures.h"
#include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
#include "third_party/WebKit/WebKit/chromium/public/WebSettings.h"
#include "third_party/WebKit/WebKit/chromium/public/WebString.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
#include "webkit/glue/webkit_glue.h"

using WebKit::WebRuntimeFeatures;
using WebKit::WebSettings;
using WebKit::WebString;
using WebKit::WebURL;
using WebKit::WebView;

void WebPreferences::Apply(WebView* web_view) const {
  WebSettings* settings = web_view->settings();
  settings->setStandardFontFamily(WideToUTF16Hack(standard_font_family));
  settings->setFixedFontFamily(WideToUTF16Hack(fixed_font_family));
  settings->setSerifFontFamily(WideToUTF16Hack(serif_font_family));
  settings->setSansSerifFontFamily(WideToUTF16Hack(sans_serif_font_family));
  settings->setCursiveFontFamily(WideToUTF16Hack(cursive_font_family));
  settings->setFantasyFontFamily(WideToUTF16Hack(fantasy_font_family));
  settings->setDefaultFontSize(default_font_size);
  settings->setDefaultFixedFontSize(default_fixed_font_size);
  settings->setMinimumFontSize(minimum_font_size);
  settings->setMinimumLogicalFontSize(minimum_logical_font_size);
  settings->setDefaultTextEncodingName(ASCIIToUTF16(default_encoding));
  settings->setJavaScriptEnabled(javascript_enabled);
  settings->setWebSecurityEnabled(web_security_enabled);
  settings->setJavaScriptCanOpenWindowsAutomatically(
      javascript_can_open_windows_automatically);
  settings->setLoadsImagesAutomatically(loads_images_automatically);
  settings->setPluginsEnabled(plugins_enabled);
  settings->setDOMPasteAllowed(dom_paste_enabled);
  settings->setDeveloperExtrasEnabled(developer_extras_enabled);
  settings->setNeedsSiteSpecificQuirks(site_specific_quirks_enabled);
  settings->setShrinksStandaloneImagesToFit(shrinks_standalone_images_to_fit);
  settings->setUsesEncodingDetector(uses_universal_detector);
  settings->setTextAreasAreResizable(text_areas_are_resizable);
  settings->setAllowScriptsToCloseWindows(allow_scripts_to_close_windows);
  if (user_style_sheet_enabled)
    settings->setUserStyleSheetLocation(user_style_sheet_location);
  else
    settings->setUserStyleSheetLocation(WebURL());
  settings->setAuthorAndUserStylesEnabled(author_and_user_styles_enabled);
  settings->setUsesPageCache(uses_page_cache);
  settings->setDownloadableBinaryFontsEnabled(remote_fonts_enabled);
  settings->setJavaScriptCanAccessClipboard(javascript_can_access_clipboard);
  settings->setXSSAuditorEnabled(xss_auditor_enabled);
  settings->setLocalStorageEnabled(local_storage_enabled);
  WebRuntimeFeatures::enableDatabase(
      WebRuntimeFeatures::isDatabaseEnabled() || databases_enabled);
  settings->setOfflineWebApplicationCacheEnabled(application_cache_enabled);
  settings->setHTML5ParserEnabled(enable_html5_parser);

  // This setting affects the behavior of links in an editable region:
  // clicking the link should select it rather than navigate to it.
  // Safari uses the same default. It is unlikley an embedder would want to
  // change this, since it would break existing rich text editors.
  settings->setEditableLinkBehaviorNeverLive();

  settings->setFontRenderingModeNormal();
  settings->setJavaEnabled(java_enabled);

  // Turn this on to cause WebCore to paint the resize corner for us.
  settings->setShouldPaintCustomScrollbars(true);

  // By default, allow_universal_access_from_file_urls is set to false and thus
  // we mitigate attacks from local HTML files by not granting file:// URLs
  // universal access. Only test shell will enable this.
  settings->setAllowUniversalAccessFromFileURLs(
      allow_universal_access_from_file_urls);
  settings->setAllowFileAccessFromFileURLs(allow_file_access_from_file_urls);

  // We prevent WebKit from checking if it needs to add a "text direction"
  // submenu to a context menu. it is not only because we don't need the result
  // but also because it cause a possible crash in Editor::hasBidiSelection().
  settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();

  // Enable experimental WebGL support if requested on command line
  // and support is compiled in.
  settings->setExperimentalWebGLEnabled(
      WebRuntimeFeatures::isWebGLEnabled() || experimental_webgl_enabled);

  // Display colored borders around composited render layers if requested
  // on command line.
  settings->setShowDebugBorders(show_composited_layer_borders);

  // Enable gpu-accelerated compositing if requested on the command line.
  settings->setAcceleratedCompositingEnabled(accelerated_compositing_enabled);

  // Enable gpu-accelerated 2d canvas if requested on the command line.
  settings->setAccelerated2dCanvasEnabled(accelerated_2d_canvas_enabled);

  // Enable memory info reporting to page if requested on the command line.
  settings->setMemoryInfoEnabled(memory_info_enabled);

  for (WebInspectorPreferences::const_iterator it = inspector_settings.begin();
       it != inspector_settings.end(); ++it)
    web_view->setInspectorSetting(WebString::fromUTF8(it->first),
                                  WebString::fromUTF8(it->second));

  // Tabs to link is not part of the settings. WebCore calls
  // ChromeClient::tabsToLinks which is part of the glue code.
  web_view->setTabsToLinks(tabs_to_links);
}
<|endoftext|>


<commit_before>#include <bench/tests/qdb/quasardb_facade.hpp>
#include <utils/detailed_error.hpp>
#ifdef WIN32
#include <utils/win32.hpp>
#endif
#include <utils/invocation_string.hpp>

#include <qdb/blob.h>
#include <qdb/deque.h>
#include <qdb/hset.h>
#include <qdb/integer.h>
#include <qdb/stream.h>
#include <qdb/tag.h>

#include <cppformat/format.h>

#ifndef WIN32
#include <cstring>
#include <cerrno>
#endif

using namespace bench::tests::qdb;

#define ARG0(x, ...) x
#define STR0(x) #x
#define STR1(x) STR0(x)
#define INVOKE(...) named_invoke(STR1(ARG0(__VA_ARGS__, )), __VA_ARGS__)

using namespace bench::tests::qdb;

static bool is_error(qdb_error_t err)
{
    switch (err)
    {
    case qdb_e_ok:
    case qdb_e_ok_created:
    case qdb_e_element_already_exists:
    case qdb_e_element_not_found:
        return false;
    default:
        return true;
    }
}

template <typename Function, typename... Args>
static qdb_error_t named_invoke(const char * name, Function function, Args &&... args)
{
    qdb_error_t err = function(args...);
    if (is_error(err))
    {
        std::string message = qdb_error(err);
        std::string details =
            fmt::format("{} returned {:#08x}", utils::make_invocation_string(name, std::forward<Args>(args)...),
                        std::uint32_t(err));

        if ((err == qdb_e_system_local) || (err == qdb_e_system_remote))
        {
#ifdef WIN32
            std::uint32_t lastError = utils::win32::get_last_error();
            message = utils::win32::get_error_string(lastError);
            details += fmt::format(" and GetLastError() returned {}", lastError);
#else
            message = std::strerror(errno);
            details += fmt::format(" and errno equals {}", errno);
#endif
        }

        throw utils::detailed_error(message, details);
    }
    return err;
}

quasardb_facade::quasardb_facade()
{
    _handle = qdb_open_tcp();
}

quasardb_facade::~quasardb_facade()
{
    qdb_close(_handle);
}

void quasardb_facade::connect(const std::string & cluster_uri)
{
    INVOKE(qdb_connect, _handle, cluster_uri.c_str());
}

void quasardb_facade::close()
{
    INVOKE(qdb_close, _handle);
}

void quasardb_facade::trim_all(int timeout)
{
    INVOKE(qdb_trim_all, _handle, timeout);
}

void quasardb_facade::free_buffer(const char * buffer)
{
    qdb_free_buffer(_handle, buffer);
}

std::string quasardb_facade::node_status(const std::string & node_uri) const
{
    const char * content;
    size_t content_size;
    INVOKE(qdb_node_status, _handle, node_uri.c_str(), &content, &content_size);
    std::string json(content, content_size);
    qdb_free_buffer(_handle, content);
    return json;
}

std::string quasardb_facade::node_topology(const std::string & node_uri) const
{
    const char * content;
    size_t content_size;
    INVOKE(qdb_node_topology, _handle, node_uri.c_str(), &content, &content_size);
    std::string json(content, content_size);
    qdb_free_buffer(_handle, content);
    return json;
}

void quasardb_facade::blob_put(const std::string & alias, const std::string & content)
{
    INVOKE(qdb_blob_put, _handle, alias.c_str(), content.data(), content.size(), qdb_never_expires);
}

bool quasardb_facade::blob_update(const std::string & alias, const std::string & content)
{
    return INVOKE(qdb_blob_update, _handle, alias.c_str(), content.data(), content.size(), qdb_preserve_expiration)
           == qdb_e_ok_created;
}

qdb_buffer quasardb_facade::blob_get(const std::string & alias)
{
    const void * result;
    std::size_t result_size;
    INVOKE(qdb_blob_get, _handle, alias.c_str(), &result, &result_size);
    return qdb_buffer(_handle, result, result_size);
}

void quasardb_facade::blob_get_noalloc(const std::string & alias, std::string & content)
{
    std::size_t result_size = content.capacity();
    INVOKE(qdb_blob_get_noalloc, _handle, alias.c_str(), const_cast<char *>(content.data()), &result_size);
    content.resize(result_size);
}

void quasardb_facade::remove(const std::string & alias)
{
    INVOKE(qdb_remove, _handle, alias.c_str());
}

qdb_buffer quasardb_facade::deque_pop_back(const std::string & alias)
{
    const void * result;
    std::size_t result_size;
    INVOKE(qdb_deque_pop_back, _handle, alias.c_str(), &result, &result_size);
    return qdb_buffer(_handle, result, result_size);
}

qdb_buffer quasardb_facade::deque_pop_front(const std::string & alias)
{
    const void * result;
    std::size_t result_size;
    INVOKE(qdb_deque_pop_front, _handle, alias.c_str(), &result, &result_size);
    return qdb_buffer(_handle, result, result_size);
}

void quasardb_facade::deque_push_back(const std::string & alias, const std::string & content)
{
    INVOKE(qdb_deque_push_back, _handle, alias.c_str(), content.data(), content.size());
}

void quasardb_facade::deque_push_front(const std::string & alias, const std::string & content)
{
    INVOKE(qdb_deque_push_front, _handle, alias.c_str(), content.data(), content.size());
}

std::int64_t quasardb_facade::int_add(const std::string & alias, std::int64_t value)
{
    std::int64_t total;
    INVOKE(qdb_int_add, _handle, alias.c_str(), 1, &total);
    return total;
}

void quasardb_facade::int_put(const std::string & alias, std::int64_t value)
{
    INVOKE(qdb_int_put, _handle, alias.c_str(), value, qdb_never_expires);
}

bool quasardb_facade::int_update(const std::string & alias, std::int64_t value)
{
    return INVOKE(qdb_int_update, _handle, alias.c_str(), value, qdb_preserve_expiration) == qdb_e_ok_created;
}

std::int64_t quasardb_facade::int_get(const std::string & alias)
{
    std::int64_t value;
    INVOKE(qdb_int_get, _handle, alias.c_str(), &value);
    return value;
}

bool quasardb_facade::hset_contains(const std::string & alias, const std::string & content)
{
    return INVOKE(qdb_hset_contains, _handle, alias.c_str(), content.data(), content.size())
           == qdb_e_element_already_exists;
}

bool quasardb_facade::hset_erase(const std::string & alias, const std::string & content)
{
    return INVOKE(qdb_hset_contains, _handle, alias.c_str(), content.data(), content.size()) != qdb_e_element_not_found;
}

bool quasardb_facade::hset_insert(const std::string & alias, const std::string & content)
{
    return INVOKE(qdb_hset_insert, _handle, alias.c_str(), content.data(), content.size())
           != qdb_e_element_already_exists;
}

void quasardb_facade::attach_tag(const std::string & alias, const std::string & tag)
{
    INVOKE(qdb_attach_tag, _handle, alias.c_str(), tag.c_str());
}

void quasardb_facade::has_tag(const std::string & alias, const std::string & tag)
{
    INVOKE(qdb_has_tag, _handle, alias.c_str(), tag.c_str());
}

void quasardb_facade::detach_tag(const std::string & alias, const std::string & tag)
{
    INVOKE(qdb_detach_tag, _handle, alias.c_str(), tag.c_str());
}

qdb_stream_t quasardb_facade::stream_open(const std::string & alias, qdb_stream_mode_t mode)
{
    qdb_stream_t stream;
    INVOKE(qdb_stream_open, _handle, alias.c_str(), mode, &stream);
    return stream;
}

void qdb_stream_facade::close()
{
    INVOKE(qdb_stream_close, _handle);
}

void qdb_stream_facade::write(const std::string & content)
{
    INVOKE(qdb_stream_write, _handle, content.data(), content.size());
}
<commit_msg>Add missing include.<commit_after>#include <bench/tests/qdb/quasardb_facade.hpp>
#include <utils/detailed_error.hpp>
#ifdef WIN32
#include <utils/win32.hpp>
#endif
#include <utils/invocation_string.hpp>

#include <qdb/blob.h>
#include <qdb/deque.h>
#include <qdb/hset.h>
#include <qdb/node.h>
#include <qdb/integer.h>
#include <qdb/stream.h>
#include <qdb/tag.h>

#include <cppformat/format.h>

#ifndef WIN32
#include <cstring>
#include <cerrno>
#endif

using namespace bench::tests::qdb;

#define ARG0(x, ...) x
#define STR0(x) #x
#define STR1(x) STR0(x)
#define INVOKE(...) named_invoke(STR1(ARG0(__VA_ARGS__, )), __VA_ARGS__)

using namespace bench::tests::qdb;

static bool is_error(qdb_error_t err)
{
    switch (err)
    {
    case qdb_e_ok:
    case qdb_e_ok_created:
    case qdb_e_element_already_exists:
    case qdb_e_element_not_found:
        return false;
    default:
        return true;
    }
}

template <typename Function, typename... Args>
static qdb_error_t named_invoke(const char * name, Function function, Args &&... args)
{
    qdb_error_t err = function(args...);
    if (is_error(err))
    {
        std::string message = qdb_error(err);
        std::string details =
            fmt::format("{} returned {:#08x}", utils::make_invocation_string(name, std::forward<Args>(args)...),
                        std::uint32_t(err));

        if ((err == qdb_e_system_local) || (err == qdb_e_system_remote))
        {
#ifdef WIN32
            std::uint32_t lastError = utils::win32::get_last_error();
            message = utils::win32::get_error_string(lastError);
            details += fmt::format(" and GetLastError() returned {}", lastError);
#else
            message = std::strerror(errno);
            details += fmt::format(" and errno equals {}", errno);
#endif
        }

        throw utils::detailed_error(message, details);
    }
    return err;
}

quasardb_facade::quasardb_facade()
{
    _handle = qdb_open_tcp();
}

quasardb_facade::~quasardb_facade()
{
    qdb_close(_handle);
}

void quasardb_facade::connect(const std::string & cluster_uri)
{
    INVOKE(qdb_connect, _handle, cluster_uri.c_str());
}

void quasardb_facade::close()
{
    INVOKE(qdb_close, _handle);
}

void quasardb_facade::trim_all(int timeout)
{
    INVOKE(qdb_trim_all, _handle, timeout);
}

void quasardb_facade::free_buffer(const char * buffer)
{
    qdb_free_buffer(_handle, buffer);
}

std::string quasardb_facade::node_status(const std::string & node_uri) const
{
    const char * content;
    size_t content_size;
    INVOKE(qdb_node_status, _handle, node_uri.c_str(), &content, &content_size);
    std::string json(content, content_size);
    qdb_free_buffer(_handle, content);
    return json;
}

std::string quasardb_facade::node_topology(const std::string & node_uri) const
{
    const char * content;
    size_t content_size;
    INVOKE(qdb_node_topology, _handle, node_uri.c_str(), &content, &content_size);
    std::string json(content, content_size);
    qdb_free_buffer(_handle, content);
    return json;
}

void quasardb_facade::blob_put(const std::string & alias, const std::string & content)
{
    INVOKE(qdb_blob_put, _handle, alias.c_str(), content.data(), content.size(), qdb_never_expires);
}

bool quasardb_facade::blob_update(const std::string & alias, const std::string & content)
{
    return INVOKE(qdb_blob_update, _handle, alias.c_str(), content.data(), content.size(), qdb_preserve_expiration)
           == qdb_e_ok_created;
}

qdb_buffer quasardb_facade::blob_get(const std::string & alias)
{
    const void * result;
    std::size_t result_size;
    INVOKE(qdb_blob_get, _handle, alias.c_str(), &result, &result_size);
    return qdb_buffer(_handle, result, result_size);
}

void quasardb_facade::blob_get_noalloc(const std::string & alias, std::string & content)
{
    std::size_t result_size = content.capacity();
    INVOKE(qdb_blob_get_noalloc, _handle, alias.c_str(), const_cast<char *>(content.data()), &result_size);
    content.resize(result_size);
}

void quasardb_facade::remove(const std::string & alias)
{
    INVOKE(qdb_remove, _handle, alias.c_str());
}

qdb_buffer quasardb_facade::deque_pop_back(const std::string & alias)
{
    const void * result;
    std::size_t result_size;
    INVOKE(qdb_deque_pop_back, _handle, alias.c_str(), &result, &result_size);
    return qdb_buffer(_handle, result, result_size);
}

qdb_buffer quasardb_facade::deque_pop_front(const std::string & alias)
{
    const void * result;
    std::size_t result_size;
    INVOKE(qdb_deque_pop_front, _handle, alias.c_str(), &result, &result_size);
    return qdb_buffer(_handle, result, result_size);
}

void quasardb_facade::deque_push_back(const std::string & alias, const std::string & content)
{
    INVOKE(qdb_deque_push_back, _handle, alias.c_str(), content.data(), content.size());
}

void quasardb_facade::deque_push_front(const std::string & alias, const std::string & content)
{
    INVOKE(qdb_deque_push_front, _handle, alias.c_str(), content.data(), content.size());
}

std::int64_t quasardb_facade::int_add(const std::string & alias, std::int64_t value)
{
    std::int64_t total;
    INVOKE(qdb_int_add, _handle, alias.c_str(), 1, &total);
    return total;
}

void quasardb_facade::int_put(const std::string & alias, std::int64_t value)
{
    INVOKE(qdb_int_put, _handle, alias.c_str(), value, qdb_never_expires);
}

bool quasardb_facade::int_update(const std::string & alias, std::int64_t value)
{
    return INVOKE(qdb_int_update, _handle, alias.c_str(), value, qdb_preserve_expiration) == qdb_e_ok_created;
}

std::int64_t quasardb_facade::int_get(const std::string & alias)
{
    std::int64_t value;
    INVOKE(qdb_int_get, _handle, alias.c_str(), &value);
    return value;
}

bool quasardb_facade::hset_contains(const std::string & alias, const std::string & content)
{
    return INVOKE(qdb_hset_contains, _handle, alias.c_str(), content.data(), content.size())
           == qdb_e_element_already_exists;
}

bool quasardb_facade::hset_erase(const std::string & alias, const std::string & content)
{
    return INVOKE(qdb_hset_contains, _handle, alias.c_str(), content.data(), content.size()) != qdb_e_element_not_found;
}

bool quasardb_facade::hset_insert(const std::string & alias, const std::string & content)
{
    return INVOKE(qdb_hset_insert, _handle, alias.c_str(), content.data(), content.size())
           != qdb_e_element_already_exists;
}

void quasardb_facade::attach_tag(const std::string & alias, const std::string & tag)
{
    INVOKE(qdb_attach_tag, _handle, alias.c_str(), tag.c_str());
}

void quasardb_facade::has_tag(const std::string & alias, const std::string & tag)
{
    INVOKE(qdb_has_tag, _handle, alias.c_str(), tag.c_str());
}

void quasardb_facade::detach_tag(const std::string & alias, const std::string & tag)
{
    INVOKE(qdb_detach_tag, _handle, alias.c_str(), tag.c_str());
}

qdb_stream_t quasardb_facade::stream_open(const std::string & alias, qdb_stream_mode_t mode)
{
    qdb_stream_t stream;
    INVOKE(qdb_stream_open, _handle, alias.c_str(), mode, &stream);
    return stream;
}

void qdb_stream_facade::close()
{
    INVOKE(qdb_stream_close, _handle);
}

void qdb_stream_facade::write(const std::string & content)
{
    INVOKE(qdb_stream_write, _handle, content.data(), content.size());
}
<|endoftext|>


<commit_before>#include <isl/set.h>
#include <isl/union_map.h>
#include <isl/union_set.h>
#include <isl/ast_build.h>
#include <isl/schedule.h>
#include <isl/schedule_node.h>

#include <coli/debug.h>
#include <coli/core.h>

#include <string.h>
#include <Halide.h>
#include "halide_image_io.h"

using namespace coli;

int main(int argc, char **argv)
{
    // Set default coli options.
    global::set_default_coli_options();

    coli::function gaussian_coli("gaussian_coli");

    Halide::Image<uint8_t> in_image = Halide::Tools::load_image("./images/rgb.png");
    int SIZE0 = in_image.extent(0);
    int SIZE1 = in_image.extent(1);
    int SIZE2 = in_image.extent(2);

    // Output buffers.
    int gaussian_extent_2 = SIZE2;
    int gaussian_extent_1 = SIZE1 - 8;
    int gaussian_extent_0 = SIZE0 - 8;
    coli::buffer buff_gaussian("buff_gaussian", 3, {coli::expr(gaussian_extent_2), coli::expr(gaussian_extent_1), coli::expr(gaussian_extent_0)}, coli::p_uint8, NULL, coli::a_output, &gaussian_coli);

    // Input buffers.
    int input_extent_2 = SIZE2;
    int input_extent_1 = SIZE1;
    int input_extent_0 = SIZE0;
    coli::buffer buff_input("buff_input", 3, {coli::expr(input_extent_2), coli::expr(input_extent_1), coli::expr(input_extent_0)}, coli::p_uint8, NULL, coli::a_input, &gaussian_coli);
    coli::computation input("[input_extent_2, input_extent_1, input_extent_0]->{input[i2, i1, i0]: (0 <= i2 <= (input_extent_2 + -1)) and (0 <= i1 <= (input_extent_1 + -1)) and (0 <= i0 <= (input_extent_0 + -1))}", expr(), false, coli::p_uint8, &gaussian_coli);
    input.set_access("{input[i2, i1, i0]->buff_input[i2, i1, i0]}");

    int kernelx_extent_0 = 5;
    coli::buffer buff_kernelx("buff_kernelx", 1, {coli::expr(kernelx_extent_0)}, coli::p_float32, NULL, coli::a_input, &gaussian_coli);
    coli::computation kernelx("[kernelx_extent_0]->{kernelx[i0]: (0 <= i0 <= (kernelx_extent_0 + -1))}", expr(), false, coli::p_float32, &gaussian_coli);
    kernelx.set_access("{kernelx[i0]->buff_kernelx[i0]}");

    int kernely_extent_0 = 5;
    coli::buffer buff_kernely("buff_kernely", 1, {coli::expr(kernely_extent_0)}, coli::p_float32, NULL, coli::a_input, &gaussian_coli);
    coli::computation kernely("[kernely_extent_0]->{kernely[i0]: (0 <= i0 <= (kernely_extent_0 + -1))}", expr(), false, coli::p_float32, &gaussian_coli);
    kernely.set_access("{kernely[i0]->buff_kernely[i0]}");

    // Define temporary buffers for "gaussian_x".
    coli::buffer buff_gaussian_x("buff_gaussian_x", 3, {coli::expr(gaussian_extent_2), (coli::expr(gaussian_extent_1) + coli::expr((int32_t)4)), coli::expr(gaussian_extent_0)}, coli::p_float32, NULL, coli::a_temporary, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_x_s0_c".
    coli::constant gaussian_x_s0_c_loop_min("gaussian_x_s0_c_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_x_s0_c_loop_extent("gaussian_x_s0_c_loop_extent", coli::expr(gaussian_extent_2), coli::p_int32, true, NULL, 0, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_x_s0_y".
    coli::constant gaussian_x_s0_y_loop_min("gaussian_x_s0_y_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_x_s0_y_loop_extent("gaussian_x_s0_y_loop_extent", (coli::expr(gaussian_extent_1) + coli::expr((int32_t)4)), coli::p_int32, true, NULL, 0, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_x_s0_x".
    coli::constant gaussian_x_s0_x_loop_min("gaussian_x_s0_x_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_x_s0_x_loop_extent("gaussian_x_s0_x_loop_extent", coli::expr(gaussian_extent_0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::computation gaussian_x_s0("[gaussian_x_s0_c_loop_min, gaussian_x_s0_c_loop_extent, gaussian_x_s0_y_loop_min, gaussian_x_s0_y_loop_extent, gaussian_x_s0_x_loop_min, gaussian_x_s0_x_loop_extent]->{gaussian_x_s0[gaussian_x_s0_c, gaussian_x_s0_y, gaussian_x_s0_x]: "
                        "(gaussian_x_s0_c_loop_min <= gaussian_x_s0_c <= ((gaussian_x_s0_c_loop_min + gaussian_x_s0_c_loop_extent) + -1)) and (gaussian_x_s0_y_loop_min <= gaussian_x_s0_y <= ((gaussian_x_s0_y_loop_min + gaussian_x_s0_y_loop_extent) + -1)) and (gaussian_x_s0_x_loop_min <= gaussian_x_s0_x <= ((gaussian_x_s0_x_loop_min + gaussian_x_s0_x_loop_extent) + -1))}",
                        (((((coli::expr((float)0) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)0))))*kernelx(coli::expr((int32_t)0)))) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)1))))*kernelx(coli::expr((int32_t)1)))) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)2))))*kernelx(coli::expr((int32_t)2)))) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)3))))*kernelx(coli::expr((int32_t)3)))) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)4))))*kernelx(coli::expr((int32_t)4)))), true, coli::p_float32, &gaussian_coli);
    gaussian_x_s0.set_access("{gaussian_x_s0[gaussian_x_s0_c, gaussian_x_s0_y, gaussian_x_s0_x]->buff_gaussian_x[gaussian_x_s0_c, gaussian_x_s0_y, gaussian_x_s0_x]}");

    // Define compute level for "gaussian_x".
    gaussian_x_s0.first(computation::root_dimension);

    // Define loop bounds for dimension "gaussian_s0_c".
    coli::constant gaussian_s0_c_loop_min("gaussian_s0_c_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_s0_c_loop_extent("gaussian_s0_c_loop_extent", coli::expr(gaussian_extent_2), coli::p_int32, true, NULL, 0, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_s0_y".
    coli::constant gaussian_s0_y_loop_min("gaussian_s0_y_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_s0_y_loop_extent("gaussian_s0_y_loop_extent", coli::expr(gaussian_extent_1), coli::p_int32, true, NULL, 0, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_s0_x".
    coli::constant gaussian_s0_x_loop_min("gaussian_s0_x_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_s0_x_loop_extent("gaussian_s0_x_loop_extent", coli::expr(gaussian_extent_0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::computation gaussian_s0("[gaussian_s0_c_loop_min, gaussian_s0_c_loop_extent, gaussian_s0_y_loop_min, gaussian_s0_y_loop_extent, gaussian_s0_x_loop_min, gaussian_s0_x_loop_extent]->{gaussian_s0[gaussian_s0_c, gaussian_s0_y, gaussian_s0_x]: "
                        "(gaussian_s0_c_loop_min <= gaussian_s0_c <= ((gaussian_s0_c_loop_min + gaussian_s0_c_loop_extent) + -1)) and (gaussian_s0_y_loop_min <= gaussian_s0_y <= ((gaussian_s0_y_loop_min + gaussian_s0_y_loop_extent) + -1)) and (gaussian_s0_x_loop_min <= gaussian_s0_x <= ((gaussian_s0_x_loop_min + gaussian_s0_x_loop_extent) + -1))}",
                        coli::expr(coli::o_cast, coli::p_uint8, (((((coli::expr((float)0) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)0)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)0)))) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)1)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)1)))) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)2)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)2)))) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)3)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)3)))) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)4)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)4))))), true, coli::p_uint8, &gaussian_coli);
    gaussian_s0.set_access("{gaussian_s0[gaussian_s0_c, gaussian_s0_y, gaussian_s0_x]->buff_gaussian[gaussian_s0_c, gaussian_s0_y, gaussian_s0_x]}");

    // Define compute level for "gaussian".
    gaussian_s0.after(gaussian_x_s0, computation::root_dimension);

    // Add schedules.

    gaussian_coli.set_arguments({&buff_input, &buff_kernelx, &buff_kernely, &buff_gaussian});
    gaussian_coli.gen_time_processor_domain();
    gaussian_coli.gen_isl_ast();
    gaussian_coli.gen_halide_stmt();
    gaussian_coli.dump_halide_stmt();
    gaussian_coli.gen_halide_obj("build/generated_fct_gaussian_coli.o");

    return 0;
}
<commit_msg>Call .first later<commit_after>#include <isl/set.h>
#include <isl/union_map.h>
#include <isl/union_set.h>
#include <isl/ast_build.h>
#include <isl/schedule.h>
#include <isl/schedule_node.h>

#include <coli/debug.h>
#include <coli/core.h>

#include <string.h>
#include <Halide.h>
#include "halide_image_io.h"

using namespace coli;

int main(int argc, char **argv)
{
    // Set default coli options.
    global::set_default_coli_options();

    coli::function gaussian_coli("gaussian_coli");

    Halide::Image<uint8_t> in_image = Halide::Tools::load_image("./images/rgb.png");
    int SIZE0 = in_image.extent(0);
    int SIZE1 = in_image.extent(1);
    int SIZE2 = in_image.extent(2);

    // Output buffers.
    int gaussian_extent_2 = SIZE2;
    int gaussian_extent_1 = SIZE1 - 8;
    int gaussian_extent_0 = SIZE0 - 8;
    coli::buffer buff_gaussian("buff_gaussian", 3, {coli::expr(gaussian_extent_2), coli::expr(gaussian_extent_1), coli::expr(gaussian_extent_0)}, coli::p_uint8, NULL, coli::a_output, &gaussian_coli);

    // Input buffers.
    int input_extent_2 = SIZE2;
    int input_extent_1 = SIZE1;
    int input_extent_0 = SIZE0;
    coli::buffer buff_input("buff_input", 3, {coli::expr(input_extent_2), coli::expr(input_extent_1), coli::expr(input_extent_0)}, coli::p_uint8, NULL, coli::a_input, &gaussian_coli);
    coli::computation input("[input_extent_2, input_extent_1, input_extent_0]->{input[i2, i1, i0]: (0 <= i2 <= (input_extent_2 + -1)) and (0 <= i1 <= (input_extent_1 + -1)) and (0 <= i0 <= (input_extent_0 + -1))}", expr(), false, coli::p_uint8, &gaussian_coli);
    input.set_access("{input[i2, i1, i0]->buff_input[i2, i1, i0]}");

    int kernelx_extent_0 = 5;
    coli::buffer buff_kernelx("buff_kernelx", 1, {coli::expr(kernelx_extent_0)}, coli::p_float32, NULL, coli::a_input, &gaussian_coli);
    coli::computation kernelx("[kernelx_extent_0]->{kernelx[i0]: (0 <= i0 <= (kernelx_extent_0 + -1))}", expr(), false, coli::p_float32, &gaussian_coli);
    kernelx.set_access("{kernelx[i0]->buff_kernelx[i0]}");

    int kernely_extent_0 = 5;
    coli::buffer buff_kernely("buff_kernely", 1, {coli::expr(kernely_extent_0)}, coli::p_float32, NULL, coli::a_input, &gaussian_coli);
    coli::computation kernely("[kernely_extent_0]->{kernely[i0]: (0 <= i0 <= (kernely_extent_0 + -1))}", expr(), false, coli::p_float32, &gaussian_coli);
    kernely.set_access("{kernely[i0]->buff_kernely[i0]}");

    // Define temporary buffers for "gaussian_x".
    coli::buffer buff_gaussian_x("buff_gaussian_x", 3, {coli::expr(gaussian_extent_2), (coli::expr(gaussian_extent_1) + coli::expr((int32_t)4)), coli::expr(gaussian_extent_0)}, coli::p_float32, NULL, coli::a_temporary, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_x_s0_c".
    coli::constant gaussian_x_s0_c_loop_min("gaussian_x_s0_c_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_x_s0_c_loop_extent("gaussian_x_s0_c_loop_extent", coli::expr(gaussian_extent_2), coli::p_int32, true, NULL, 0, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_x_s0_y".
    coli::constant gaussian_x_s0_y_loop_min("gaussian_x_s0_y_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_x_s0_y_loop_extent("gaussian_x_s0_y_loop_extent", (coli::expr(gaussian_extent_1) + coli::expr((int32_t)4)), coli::p_int32, true, NULL, 0, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_x_s0_x".
    coli::constant gaussian_x_s0_x_loop_min("gaussian_x_s0_x_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_x_s0_x_loop_extent("gaussian_x_s0_x_loop_extent", coli::expr(gaussian_extent_0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::computation gaussian_x_s0("[gaussian_x_s0_c_loop_min, gaussian_x_s0_c_loop_extent, gaussian_x_s0_y_loop_min, gaussian_x_s0_y_loop_extent, gaussian_x_s0_x_loop_min, gaussian_x_s0_x_loop_extent]->{gaussian_x_s0[gaussian_x_s0_c, gaussian_x_s0_y, gaussian_x_s0_x]: "
                        "(gaussian_x_s0_c_loop_min <= gaussian_x_s0_c <= ((gaussian_x_s0_c_loop_min + gaussian_x_s0_c_loop_extent) + -1)) and (gaussian_x_s0_y_loop_min <= gaussian_x_s0_y <= ((gaussian_x_s0_y_loop_min + gaussian_x_s0_y_loop_extent) + -1)) and (gaussian_x_s0_x_loop_min <= gaussian_x_s0_x <= ((gaussian_x_s0_x_loop_min + gaussian_x_s0_x_loop_extent) + -1))}",
                        (((((coli::expr((float)0) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)0))))*kernelx(coli::expr((int32_t)0)))) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)1))))*kernelx(coli::expr((int32_t)1)))) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)2))))*kernelx(coli::expr((int32_t)2)))) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)3))))*kernelx(coli::expr((int32_t)3)))) + (coli::expr(coli::o_cast, coli::p_float32, input(coli::idx("gaussian_x_s0_c"), coli::idx("gaussian_x_s0_y"), (coli::idx("gaussian_x_s0_x") + coli::expr((int32_t)4))))*kernelx(coli::expr((int32_t)4)))), true, coli::p_float32, &gaussian_coli);
    gaussian_x_s0.set_access("{gaussian_x_s0[gaussian_x_s0_c, gaussian_x_s0_y, gaussian_x_s0_x]->buff_gaussian_x[gaussian_x_s0_c, gaussian_x_s0_y, gaussian_x_s0_x]}");

    // Define loop bounds for dimension "gaussian_s0_c".
    coli::constant gaussian_s0_c_loop_min("gaussian_s0_c_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_s0_c_loop_extent("gaussian_s0_c_loop_extent", coli::expr(gaussian_extent_2), coli::p_int32, true, NULL, 0, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_s0_y".
    coli::constant gaussian_s0_y_loop_min("gaussian_s0_y_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_s0_y_loop_extent("gaussian_s0_y_loop_extent", coli::expr(gaussian_extent_1), coli::p_int32, true, NULL, 0, &gaussian_coli);

    // Define loop bounds for dimension "gaussian_s0_x".
    coli::constant gaussian_s0_x_loop_min("gaussian_s0_x_loop_min", coli::expr((int32_t)0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::constant gaussian_s0_x_loop_extent("gaussian_s0_x_loop_extent", coli::expr(gaussian_extent_0), coli::p_int32, true, NULL, 0, &gaussian_coli);
    coli::computation gaussian_s0("[gaussian_s0_c_loop_min, gaussian_s0_c_loop_extent, gaussian_s0_y_loop_min, gaussian_s0_y_loop_extent, gaussian_s0_x_loop_min, gaussian_s0_x_loop_extent]->{gaussian_s0[gaussian_s0_c, gaussian_s0_y, gaussian_s0_x]: "
                        "(gaussian_s0_c_loop_min <= gaussian_s0_c <= ((gaussian_s0_c_loop_min + gaussian_s0_c_loop_extent) + -1)) and (gaussian_s0_y_loop_min <= gaussian_s0_y <= ((gaussian_s0_y_loop_min + gaussian_s0_y_loop_extent) + -1)) and (gaussian_s0_x_loop_min <= gaussian_s0_x <= ((gaussian_s0_x_loop_min + gaussian_s0_x_loop_extent) + -1))}",
                        coli::expr(coli::o_cast, coli::p_uint8, (((((coli::expr((float)0) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)0)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)0)))) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)1)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)1)))) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)2)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)2)))) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)3)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)3)))) + (gaussian_x_s0(coli::idx("gaussian_s0_c"), (coli::idx("gaussian_s0_y") + coli::expr((int32_t)4)), coli::idx("gaussian_s0_x"))*kernely(coli::expr((int32_t)4))))), true, coli::p_uint8, &gaussian_coli);
    gaussian_s0.set_access("{gaussian_s0[gaussian_s0_c, gaussian_s0_y, gaussian_s0_x]->buff_gaussian[gaussian_s0_c, gaussian_s0_y, gaussian_s0_x]}");

    // Define compute level for "gaussian_x".
    gaussian_x_s0.first(computation::root_dimension);
    // Define compute level for "gaussian".
    gaussian_s0.after(gaussian_x_s0, computation::root_dimension);

    // Add schedules.

    gaussian_coli.set_arguments({&buff_input, &buff_kernelx, &buff_kernely, &buff_gaussian});
    gaussian_coli.gen_time_processor_domain();
    gaussian_coli.gen_isl_ast();
    gaussian_coli.gen_halide_stmt();
    gaussian_coli.dump_halide_stmt();
    gaussian_coli.gen_halide_obj("build/generated_fct_gaussian_coli.o");

    return 0;
}
<|endoftext|>


<commit_before>#include "Halide.h"
using namespace Halide;

constexpr auto block_size = 16;

int main(int argc, char **argv) {
    ImageParam in(Float(32), 2, "input");

    float alpha = 0.3;
    float beta = 0.4;

    Func heat2d("heat2dgpu");
    Var x("x"), y("y"), x0, y0, x1, y1, rx0, ry0, rx1, ry1;

    RDom r(1, in.width()-2, 1, in.height()-2);
    heat2d(x, y) = 0.0f;
    heat2d(r.x, r.y) = alpha * in(r.x, r.y) +
                       beta * (in(r.x+1, r.y) + in(r.x-1, r.y) + in(r.x, r.y+1) + in(r.x, r.y-1));

    heat2d.gpu_tile(x, y, x0, y0, x1, y1, block_size, block_size);
    heat2d.update().gpu_tile(r.x, r.y, block_size, block_size);

    Halide::Target target = Halide::get_host_target();
    target.set_feature(Target::Feature::CUDA, true);

    heat2d.compile_to_object("build/generated_fct_heat2dgpu_ref.o",
                             {in},
                             "heat2d_ref",
                             target);

    heat2d.compile_to_lowered_stmt("build/generated_fct_heat2dgpu_ref.txt",
                                   {in},
                                   Text,
                                   target);
    return 0;
}
<commit_msg>fixed heat2dgpu<commit_after>#include "Halide.h"
using namespace Halide;

constexpr auto block_size = 16;

int main(int argc, char **argv) {
    ImageParam in(Float(32), 2, "input");

    float alpha = 0.3;
    float beta = 0.4;

    Func heat2d("heat2dgpu");
    Var x("x"), y("y"), x0, y0, x1, y1, rx0, ry0, rx1, ry1;

    RDom r(1, in.width()-2, 1, in.height()-2);
    heat2d(x, y) = 0.0f;
    heat2d(r.x, r.y) = alpha * in(r.x, r.y) +
                       beta * (in(r.x+1, r.y) + in(r.x-1, r.y) + in(r.x, r.y+1) + in(r.x, r.y-1));

    heat2d.gpu_tile(x, y, x0, y0, x1, y1, block_size, block_size);
    heat2d.update().gpu_tile(r.x, r.y, block_size, block_size);

    Halide::Target target = Halide::get_host_target();
    target.set_feature(Target::Feature::CUDA, true);

    heat2d.compile_to_object("build/generated_fct_heat2dgpu_ref.o",
                             {in},
                             "heat2dgpu_ref",
                             target);

    heat2d.compile_to_lowered_stmt("build/generated_fct_heat2dgpu_ref.txt",
                                   {in},
                                   Text,
                                   target);
    return 0;
}
<|endoftext|>