<commit_before>#include "bochs.h"
#include "cpu/extdb.h"
#ifdef WIN32
#  include <windows.h>
#else
#  error "extdb.cc only supported in win32 environment"
#endif

TRegs regs;

char debug_loaded = 0;

void (*call_debugger)(TRegs *,Bit8u *, Bit32u);

#if BX_SUPPORT_X86_64

void bx_external_debugger(BX_CPU_C *cpu)
{
     //printf("Calling debugger state=%d\n",regs.debug_state);
     switch (regs.debug_state) {
     case debug_run:
       return;
     case debug_count:
       if (--regs.debug_counter) return;
       regs.debug_state = debug_step;
       break;
     case debug_skip:
       if (cpu->dword.eip != regs.debug_eip ||
           cpu->sregs[1].selector.value != regs.debug_cs) return;
       regs.debug_state = debug_step;
       break;
     }

     regs.rax = cpu->gen_reg[0].rrx;
     regs.rcx = cpu->gen_reg[1].rrx;
     regs.rdx = cpu->gen_reg[2].rrx;
     regs.rbx = cpu->gen_reg[3].rrx;
     regs.rsp = cpu->gen_reg[4].rrx;
     regs.rbp = cpu->gen_reg[5].rrx;
     regs.rsi = cpu->gen_reg[6].rrx;
     regs.rdi = cpu->gen_reg[7].rrx;
     regs.r8  = cpu->gen_reg[8].rrx;
     regs.r9  = cpu->gen_reg[9].rrx;
     regs.r10 = cpu->gen_reg[10].rrx;
     regs.r11 = cpu->gen_reg[11].rrx;
     regs.r12 = cpu->gen_reg[12].rrx;
     regs.r13 = cpu->gen_reg[13].rrx;
     regs.r14 = cpu->gen_reg[14].rrx;
     regs.r15 = cpu->gen_reg[15].rrx;
     regs.rip = cpu->rip;
     regs.rflags = cpu->read_eflags();
     regs.es = cpu->sregs[0].selector.value;
     regs.cs = cpu->sregs[1].selector.value;
     regs.ss = cpu->sregs[2].selector.value;
     regs.ds = cpu->sregs[3].selector.value;
     regs.fs = cpu->sregs[4].selector.value;
     regs.gs = cpu->sregs[5].selector.value;
     regs.gdt.base = cpu->gdtr.base;
     regs.gdt.limit = cpu->gdtr.limit;
     regs.idt.base = cpu->idtr.base;
     regs.idt.limit = cpu->idtr.limit;
     regs.ldt = cpu->ldtr.selector.value;
     regs.cr0 = cpu->cr0.val32;
     regs.cr1 = cpu->cr1;
     regs.cr2 = cpu->cr2;
     regs.cr3 = cpu->cr3;
     regs.cr4 = cpu->cr4.val32;
     //regs.cr5 = cpu->cr5;
     //regs.cr6 = cpu->cr6;
     //regs.cr7 = cpu->cr7;
     regs.efer = (BX_CPU_THIS_PTR msr.sce << 0)
               | (BX_CPU_THIS_PTR msr.lme << 8)
               | (BX_CPU_THIS_PTR msr.lma << 10);

     if (debug_loaded == 0) {
       HINSTANCE hdbg;

       debug_loaded = 1;
       hdbg = LoadLibrary("debug.dll");
       call_debugger = (void (*)(TRegs *,Bit8u *, Bit32u)) GetProcAddress(hdbg,"call_debugger");

       if (call_debugger != NULL) debug_loaded = 2;
     }
     if (debug_loaded == 2) {
       bx_vga.timer();
       call_debugger(&regs,cpu->mem->vector,cpu->mem->len);
     }
}

#else  // x86-32

void bx_external_debugger(BX_CPU_C *cpu)
{
     switch (regs.debug_state) {
     case debug_run:
       return;
     case debug_count:
       if (--regs.debug_counter) return;
       regs.debug_state = debug_step;
       break;
     case debug_skip:
       if (cpu->dword.eip != regs.debug_eip ||
           cpu->sregs[1].selector.value != regs.debug_cs) return;
       regs.debug_state = debug_step;
       break;
     }

     regs.eax = cpu->gen_reg[0].dword.erx;
     regs.ecx = cpu->gen_reg[1].dword.erx;
     regs.edx = cpu->gen_reg[2].dword.erx;
     regs.ebx = cpu->gen_reg[3].dword.erx;
     regs.esp = cpu->gen_reg[4].dword.erx;
     regs.ebp = cpu->gen_reg[5].dword.erx;
     regs.esi = cpu->gen_reg[6].dword.erx;
     regs.edi = cpu->gen_reg[7].dword.erx;
     regs.eip = cpu->dword.eip;
     regs.eflags = cpu->read_eflags();
     regs.es = cpu->sregs[0].selector.value;
     regs.cs = cpu->sregs[1].selector.value;
     regs.ss = cpu->sregs[2].selector.value;
     regs.ds = cpu->sregs[3].selector.value;
     regs.fs = cpu->sregs[4].selector.value;
     regs.gs = cpu->sregs[5].selector.value;
     regs.gdt.base = cpu->gdtr.base;
     regs.gdt.limit = cpu->gdtr.limit;
     regs.idt.base = cpu->idtr.base;
     regs.idt.limit = cpu->idtr.limit;
     regs.ldt = cpu->ldtr.selector.value;
     regs.cr0 = cpu->cr0.val32;
     regs.cr1 = cpu->cr1;
     regs.cr2 = cpu->cr2;
     regs.cr3 = cpu->cr3;

     if (debug_loaded == 0) {
       HINSTANCE hdbg;

       debug_loaded = 1;
       hdbg = LoadLibrary("debug.dll");
       call_debugger = (void (*)(TRegs *,Bit8u *, Bit32u)) GetProcAddress(hdbg,"call_debugger");

       if (call_debugger != NULL) debug_loaded = 2;
     }
     if (debug_loaded == 2) call_debugger(&regs,cpu->mem->vector,cpu->mem->len);
}

#end   // #if BX_SUPPORT_X86_64
<commit_msg>Fixed CR4 reference in extdb.cc to use the new accessor model. Also, deleted the old 32-bit path in there as Peter said it's no longer useful to him.<commit_after>#include "bochs.h"
#include "cpu/extdb.h"
#ifdef WIN32
#  include <windows.h>
#else
#  error "extdb.cc only supported in win32 environment"
#endif

TRegs regs;

char debug_loaded = 0;

void (*call_debugger)(TRegs *,Bit8u *, Bit32u);

void bx_external_debugger(BX_CPU_C *cpu)
{
     //printf("Calling debugger state=%d\n",regs.debug_state);
     switch (regs.debug_state) {
     case debug_run:
       return;
     case debug_count:
       if (--regs.debug_counter) return;
       regs.debug_state = debug_step;
       break;
     case debug_skip:
       if (cpu->dword.eip != regs.debug_eip ||
           cpu->sregs[1].selector.value != regs.debug_cs) return;
       regs.debug_state = debug_step;
       break;
     }

     regs.rax = cpu->gen_reg[0].rrx;
     regs.rcx = cpu->gen_reg[1].rrx;
     regs.rdx = cpu->gen_reg[2].rrx;
     regs.rbx = cpu->gen_reg[3].rrx;
     regs.rsp = cpu->gen_reg[4].rrx;
     regs.rbp = cpu->gen_reg[5].rrx;
     regs.rsi = cpu->gen_reg[6].rrx;
     regs.rdi = cpu->gen_reg[7].rrx;
     regs.r8  = cpu->gen_reg[8].rrx;
     regs.r9  = cpu->gen_reg[9].rrx;
     regs.r10 = cpu->gen_reg[10].rrx;
     regs.r11 = cpu->gen_reg[11].rrx;
     regs.r12 = cpu->gen_reg[12].rrx;
     regs.r13 = cpu->gen_reg[13].rrx;
     regs.r14 = cpu->gen_reg[14].rrx;
     regs.r15 = cpu->gen_reg[15].rrx;
     regs.rip = cpu->rip;
     regs.rflags = cpu->read_eflags();
     regs.es = cpu->sregs[0].selector.value;
     regs.cs = cpu->sregs[1].selector.value;
     regs.ss = cpu->sregs[2].selector.value;
     regs.ds = cpu->sregs[3].selector.value;
     regs.fs = cpu->sregs[4].selector.value;
     regs.gs = cpu->sregs[5].selector.value;
     regs.gdt.base = cpu->gdtr.base;
     regs.gdt.limit = cpu->gdtr.limit;
     regs.idt.base = cpu->idtr.base;
     regs.idt.limit = cpu->idtr.limit;
     regs.ldt = cpu->ldtr.selector.value;
     regs.cr0 = cpu->cr0.val32;
     regs.cr1 = cpu->cr1;
     regs.cr2 = cpu->cr2;
     regs.cr3 = cpu->cr3;
     regs.cr4 = cpu->cr4.getRegister();
     //regs.cr5 = cpu->cr5;
     //regs.cr6 = cpu->cr6;
     //regs.cr7 = cpu->cr7;
     regs.efer = (BX_CPU_THIS_PTR msr.sce << 0)
               | (BX_CPU_THIS_PTR msr.lme << 8)
               | (BX_CPU_THIS_PTR msr.lma << 10);

     if (debug_loaded == 0) {
       HINSTANCE hdbg;

       debug_loaded = 1;
       hdbg = LoadLibrary("debug.dll");
       call_debugger = (void (*)(TRegs *,Bit8u *, Bit32u)) GetProcAddress(hdbg,"call_debugger");

       if (call_debugger != NULL) debug_loaded = 2;
     }
     if (debug_loaded == 2) {
       bx_vga.timer();
       call_debugger(&regs,cpu->mem->vector,cpu->mem->len);
     }
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef CONNECTION_HPP
#define CONNECTION_HPP

#include <mapnik/datasource.hpp>
#include <boost/make_shared.hpp>

// std
#include <sstream>
#include <iostream>

extern "C" {
#include "libpq-fe.h"
}

#include "resultset.hpp"

class Connection
{
private:
    PGconn *conn_;
    int cursorId;
    bool closed_;
public:
    Connection(std::string const& connection_str)
        :cursorId(0),
         closed_(false)
    {
        conn_ = PQconnectdb(connection_str.c_str());
        if (PQstatus(conn_) != CONNECTION_OK)
        {
            // note: empty ctor is intentional here
            // as somehow constructor string can dissapear
            std::ostringstream s;
            s << "Postgis Plugin: ";
            if (conn_ )
            {
                std::string msg = PQerrorMessage( conn_ );
                if ( ! msg.empty() )
                {
                    s << msg.substr( 0, msg.size() - 1 );
                }
                else
                {
                    s << "unable to connect to postgres server";
                }
            }
            else
            {
                s << "unable to connect to postgres server";
            }
            throw mapnik::datasource_exception( s.str() );
        }
    }

    bool execute(const std::string& sql) const
    {
        PGresult *result = PQexec(conn_,sql.c_str());
        bool ok=(result && (PQresultStatus(result) == PGRES_COMMAND_OK));
        PQclear(result);
        return ok;
    }

    boost::shared_ptr<ResultSet> executeQuery(const std::string& sql,int type=0) const
    {
        PGresult *result=0;
        if (type==1)
        {
            result = PQexecParams(conn_,sql.c_str(),0,0,0,0,0,1);
        }
        else
        {
            result = PQexec(conn_,sql.c_str());
        }
        if(!result || (PQresultStatus(result) != PGRES_TUPLES_OK))
        {
            std::ostringstream s("Postgis Plugin: PSQL error");
            if (conn_ )
            {
                std::string msg = PQerrorMessage( conn_ );
                if ( ! msg.empty() )
                {
                    s << ":\n" <<  msg.substr( 0, msg.size() - 1 );
                }

                s << "\nFull sql was: '" <<  sql << "'\n";
            }
            if (result)
                PQclear(result);
            throw mapnik::datasource_exception( s.str() );
        }

        return boost::make_shared<ResultSet>(result);
    }

    std::string client_encoding() const
    {
        return PQparameterStatus(conn_,"client_encoding");
    }

    bool isOK() const
    {
        return (PQstatus(conn_) != CONNECTION_BAD);
    }

    void close()
    {
        if (!closed_)
        {
            PQfinish(conn_);
#ifdef MAPNIK_DEBUG
            std::clog << "PostGIS: datasource closed, also closing connection - " << conn_ << std::endl;
#endif
            closed_ = true;
        }
    }

    std::string new_cursor_name()
    {
        std::ostringstream s;
        s << "mapnik_" << (cursorId++);
        return s.str();
    }

    ~Connection()
    {
        if (!closed_)
        {
            PQfinish(conn_);
#ifdef MAPNIK_DEBUG
            std::clog << "PostGIS: postgresql connection closed - " << conn_ << std::endl;
#endif
            closed_ = true;
        }
    }
};

#endif //CONNECTION_HPP
<commit_msg>ensure proper error output from postgis plugin - refs #955<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef CONNECTION_HPP
#define CONNECTION_HPP

#include <mapnik/datasource.hpp>
#include <boost/make_shared.hpp>

// std
#include <sstream>
#include <iostream>

extern "C" {
#include "libpq-fe.h"
}

#include "resultset.hpp"

class Connection
{
private:
    PGconn *conn_;
    int cursorId;
    bool closed_;
public:
    Connection(std::string const& connection_str)
        :cursorId(0),
         closed_(false)
    {
        conn_ = PQconnectdb(connection_str.c_str());
        if (PQstatus(conn_) != CONNECTION_OK)
        {
            // note: empty ctor is intentional here
            // as somehow constructor string can dissapear
            std::ostringstream s;
            s << "Postgis Plugin: ";
            if (conn_ )
            {
                std::string msg = PQerrorMessage( conn_ );
                if ( ! msg.empty() )
                {
                    s << msg.substr( 0, msg.size() - 1 );
                }
                else
                {
                    s << "unable to connect to postgres server";
                }
            }
            else
            {
                s << "unable to connect to postgres server";
            }
            throw mapnik::datasource_exception( s.str() );
        }
    }

    bool execute(const std::string& sql) const
    {
        PGresult *result = PQexec(conn_,sql.c_str());
        bool ok=(result && (PQresultStatus(result) == PGRES_COMMAND_OK));
        PQclear(result);
        return ok;
    }

    boost::shared_ptr<ResultSet> executeQuery(const std::string& sql,int type=0) const
    {
        PGresult *result=0;
        if (type==1)
        {
            result = PQexecParams(conn_,sql.c_str(),0,0,0,0,0,1);
        }
        else
        {
            result = PQexec(conn_,sql.c_str());
        }
        if(!result || (PQresultStatus(result) != PGRES_TUPLES_OK))
        {
            std::ostringstream s;
            s << "Postgis Plugin: PSQL error";
            if (conn_ )
            {
                std::string msg = PQerrorMessage( conn_ );
                if ( ! msg.empty() )
                {
                    s << ":\n" <<  msg.substr( 0, msg.size() - 1 );
                }

                s << "\nFull sql was: '" <<  sql << "'\n";
            }
            else
            {
                s << "unable to connect to database";
            }
            if (result)
                PQclear(result);
            throw mapnik::datasource_exception( s.str() );
        }

        return boost::make_shared<ResultSet>(result);
    }

    std::string client_encoding() const
    {
        return PQparameterStatus(conn_,"client_encoding");
    }

    bool isOK() const
    {
        return (PQstatus(conn_) != CONNECTION_BAD);
    }

    void close()
    {
        if (!closed_)
        {
            PQfinish(conn_);
#ifdef MAPNIK_DEBUG
            std::clog << "PostGIS: datasource closed, also closing connection - " << conn_ << std::endl;
#endif
            closed_ = true;
        }
    }

    std::string new_cursor_name()
    {
        std::ostringstream s;
        s << "mapnik_" << (cursorId++);
        return s.str();
    }

    ~Connection()
    {
        if (!closed_)
        {
            PQfinish(conn_);
#ifdef MAPNIK_DEBUG
            std::clog << "PostGIS: postgresql connection closed - " << conn_ << std::endl;
#endif
            closed_ = true;
        }
    }
};

#endif //CONNECTION_HPP
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2015 Cloudius Systems
 *
 * Modified by Cloudius Systems
 */

#ifndef CQL3_TERM_HH
#define CQL3_TERM_HH

#include <memory>

namespace cql3 {

class terminal;

class term;

/**
 * A CQL3 term, i.e. a column value with or without bind variables.
 *
 * A Term can be either terminal or non terminal. A term object is one that is typed and is obtained
 * from a raw term (Term.Raw) by poviding the actual receiver to which the term is supposed to be a
 * value of.
 */
class term {
public:
    /**
     * Collects the column specification for the bind variables in this Term.
     * This is obviously a no-op if the term is Terminal.
     *
     * @param boundNames the variables specification where to collect the
     * bind variables of this term in.
     */
    virtual void collect_marker_specification(::shared_ptr<variable_specifications> bound_names) = 0;

    /**
     * Bind the values in this term to the values contained in {@code values}.
     * This is obviously a no-op if the term is Terminal.
     *
     * @param options the values to bind markers to.
     * @return the result of binding all the variables of this NonTerminal (or
     * 'this' if the term is terminal).
     */
    virtual ::shared_ptr<terminal> bind(::shared_ptr<term> term, const query_options& options) = 0;

    /**
     * A shorter for bind(values).get().
     * We expose it mainly because for constants it can avoids allocating a temporary
     * object between the bind and the get (note that we still want to be able
     * to separate bind and get for collections).
     */
    virtual bytes bind_and_get(::shared_ptr<term> term, const query_options& options) = 0;

    /**
     * Whether or not that term contains at least one bind marker.
     *
     * Note that this is slightly different from being or not a NonTerminal,
     * because calls to non pure functions will be NonTerminal (see #5616)
     * even if they don't have bind markers.
     */
    virtual bool contains_bind_marker() = 0;

    virtual bool uses_function(sstring ks_name, sstring function_name) const = 0;

    /**
     * A parsed, non prepared (thus untyped) term.
     *
     * This can be one of:
     *   - a constant
     *   - a collection literal
     *   - a function call
     *   - a marker
     */
    class raw : public virtual assignment_testable {
    public:
        /**
         * This method validates this RawTerm is valid for provided column
         * specification and "prepare" this RawTerm, returning the resulting
         * prepared Term.
         *
         * @param receiver the "column" this RawTerm is supposed to be a value of. Note
         * that the ColumnSpecification may not correspond to a real column in the
         * case this RawTerm describe a list index or a map key, etc...
         * @return the prepared term.
         */
        virtual std::unique_ptr<term> prepare(sstring keyspace, const column_specification& receiver) = 0;
    };

    class multi_column_raw : public virtual raw {
    public:
        virtual std::unique_ptr<term> prepare(sstring keyspace, const std::vector<column_specification>& receiver) = 0;
    };
};

    /**
     * A terminal term, one that can be reduced to a byte buffer directly.
     *
     * This includes most terms that don't have a bind marker (an exception
     * being delayed call for non pure function that are NonTerminal even
     * if they don't have bind markers).
     *
     * This can be only one of:
     *   - a constant value
     *   - a collection value
     *
     * Note that a terminal term will always have been type checked, and thus
     * consumer can (and should) assume so.
     */
    class terminal : public term {
    public:
        virtual void collect_marker_specification(::shared_ptr<variable_specifications> bound_names) {
        }

        virtual ::shared_ptr<terminal> bind(::shared_ptr<term> term, const query_options& options) override {
            return ::static_pointer_cast<terminal>(term);
        }

        virtual bool uses_function(sstring ks_name, sstring function_name) const override {
            return false;
        }

        // While some NonTerminal may not have bind markers, no Term can be Terminal
        // with a bind marker
        virtual bool contains_bind_marker() const {
            return false;
        }

        /**
         * @return the serialized value of this terminal.
         */
        virtual bytes get(::shared_ptr<term> term, const query_options& options) = 0;

        virtual bytes bind_and_get(::shared_ptr<term> term, const query_options& options) override {
            return get(term, options);
        }
    };

    class multi_item_terminal : public terminal {
    public:
        virtual std::vector<bytes> get_elements() = 0;
    };

    class collection_terminal {
    public:
        /** Gets the value of the collection when serialized with the given protocol version format */
        virtual bytes get_with_protocol_version(int protocol_version) = 0;
    };

    /**
     * A non terminal term, i.e. a term that can only be reduce to a byte buffer
     * at execution time.
     *
     * We have the following type of NonTerminal:
     *   - marker for a constant value
     *   - marker for a collection value (list, set, map)
     *   - a function having bind marker
     *   - a non pure function (even if it doesn't have bind marker - see #5616)
     */
    class non_terminal : public virtual term {
    public:
        virtual bool uses_function(sstring ks_name, sstring function_name) const override {
            return false;
        }

        virtual bytes bind_and_get(::shared_ptr<term> term, const query_options& options) override {
            auto t = bind(term, options);
            return t == nullptr ? nullptr : t->get(term, options);
        }
    };
}

#endif
<commit_msg>cql3: Fix term::prepare() type signature<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2015 Cloudius Systems
 *
 * Modified by Cloudius Systems
 */

#ifndef CQL3_TERM_HH
#define CQL3_TERM_HH

#include <memory>

namespace cql3 {

class terminal;

class term;

/**
 * A CQL3 term, i.e. a column value with or without bind variables.
 *
 * A Term can be either terminal or non terminal. A term object is one that is typed and is obtained
 * from a raw term (Term.Raw) by poviding the actual receiver to which the term is supposed to be a
 * value of.
 */
class term {
public:
    /**
     * Collects the column specification for the bind variables in this Term.
     * This is obviously a no-op if the term is Terminal.
     *
     * @param boundNames the variables specification where to collect the
     * bind variables of this term in.
     */
    virtual void collect_marker_specification(::shared_ptr<variable_specifications> bound_names) = 0;

    /**
     * Bind the values in this term to the values contained in {@code values}.
     * This is obviously a no-op if the term is Terminal.
     *
     * @param options the values to bind markers to.
     * @return the result of binding all the variables of this NonTerminal (or
     * 'this' if the term is terminal).
     */
    virtual ::shared_ptr<terminal> bind(::shared_ptr<term> term, const query_options& options) = 0;

    /**
     * A shorter for bind(values).get().
     * We expose it mainly because for constants it can avoids allocating a temporary
     * object between the bind and the get (note that we still want to be able
     * to separate bind and get for collections).
     */
    virtual bytes bind_and_get(::shared_ptr<term> term, const query_options& options) = 0;

    /**
     * Whether or not that term contains at least one bind marker.
     *
     * Note that this is slightly different from being or not a NonTerminal,
     * because calls to non pure functions will be NonTerminal (see #5616)
     * even if they don't have bind markers.
     */
    virtual bool contains_bind_marker() = 0;

    virtual bool uses_function(sstring ks_name, sstring function_name) const = 0;

    /**
     * A parsed, non prepared (thus untyped) term.
     *
     * This can be one of:
     *   - a constant
     *   - a collection literal
     *   - a function call
     *   - a marker
     */
    class raw : public virtual assignment_testable {
    public:
        /**
         * This method validates this RawTerm is valid for provided column
         * specification and "prepare" this RawTerm, returning the resulting
         * prepared Term.
         *
         * @param receiver the "column" this RawTerm is supposed to be a value of. Note
         * that the ColumnSpecification may not correspond to a real column in the
         * case this RawTerm describe a list index or a map key, etc...
         * @return the prepared term.
         */
        virtual ::shared_ptr<term> prepare(sstring keyspace, ::shared_ptr<column_specification> receiver) = 0;
    };

    class multi_column_raw : public virtual raw {
    public:
        virtual ::shared_ptr<term> prepare(sstring keyspace, const std::vector<column_specification>& receiver) = 0;
    };
};

    /**
     * A terminal term, one that can be reduced to a byte buffer directly.
     *
     * This includes most terms that don't have a bind marker (an exception
     * being delayed call for non pure function that are NonTerminal even
     * if they don't have bind markers).
     *
     * This can be only one of:
     *   - a constant value
     *   - a collection value
     *
     * Note that a terminal term will always have been type checked, and thus
     * consumer can (and should) assume so.
     */
    class terminal : public term {
    public:
        virtual void collect_marker_specification(::shared_ptr<variable_specifications> bound_names) {
        }

        virtual ::shared_ptr<terminal> bind(::shared_ptr<term> term, const query_options& options) override {
            return ::static_pointer_cast<terminal>(term);
        }

        virtual bool uses_function(sstring ks_name, sstring function_name) const override {
            return false;
        }

        // While some NonTerminal may not have bind markers, no Term can be Terminal
        // with a bind marker
        virtual bool contains_bind_marker() const {
            return false;
        }

        /**
         * @return the serialized value of this terminal.
         */
        virtual bytes get(::shared_ptr<term> term, const query_options& options) = 0;

        virtual bytes bind_and_get(::shared_ptr<term> term, const query_options& options) override {
            return get(term, options);
        }
    };

    class multi_item_terminal : public terminal {
    public:
        virtual std::vector<bytes> get_elements() = 0;
    };

    class collection_terminal {
    public:
        /** Gets the value of the collection when serialized with the given protocol version format */
        virtual bytes get_with_protocol_version(int protocol_version) = 0;
    };

    /**
     * A non terminal term, i.e. a term that can only be reduce to a byte buffer
     * at execution time.
     *
     * We have the following type of NonTerminal:
     *   - marker for a constant value
     *   - marker for a collection value (list, set, map)
     *   - a function having bind marker
     *   - a non pure function (even if it doesn't have bind marker - see #5616)
     */
    class non_terminal : public virtual term {
    public:
        virtual bool uses_function(sstring ks_name, sstring function_name) const override {
            return false;
        }

        virtual bytes bind_and_get(::shared_ptr<term> term, const query_options& options) override {
            auto t = bind(term, options);
            return t == nullptr ? nullptr : t->get(term, options);
        }
    };
}

#endif
<|endoftext|>


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

#include "base/threading/thread_restrictions.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/metrics/thread_watcher.h"
#include "chrome/common/notification_service.h"

// static
const int ThreadWatcher::kPingCount = 3;

//------------------------------------------------------------------------------
// ThreadWatcher methods and members.

ThreadWatcher::ThreadWatcher(const BrowserThread::ID thread_id,
                             const std::string& thread_name,
                             const base::TimeDelta& sleep_time,
                             const base::TimeDelta& unresponsive_time)
    : thread_id_(thread_id),
      thread_name_(thread_name),
      sleep_time_(sleep_time),
      unresponsive_time_(unresponsive_time),
      ping_time_(base::TimeTicks::Now()),
      ping_sequence_number_(0),
      active_(false),
      ping_count_(kPingCount),
      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
  Initialize();
}

ThreadWatcher::~ThreadWatcher() {}

// static
void ThreadWatcher::StartWatching(const BrowserThread::ID thread_id,
                                  const std::string& thread_name,
                                  const base::TimeDelta& sleep_time,
                                  const base::TimeDelta& unresponsive_time) {
  DCHECK_GE(sleep_time.InMilliseconds(), 0);
  DCHECK_GE(unresponsive_time.InMilliseconds(), sleep_time.InMilliseconds());

  // If we are not on WATCHDOG thread, then post a task to call StartWatching on
  // WATCHDOG thread.
  if (!BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)) {
    BrowserThread::PostTask(
        BrowserThread::WATCHDOG,
        FROM_HERE,
        NewRunnableFunction(
            &ThreadWatcher::StartWatching,
            thread_id, thread_name, sleep_time, unresponsive_time));
    return;
  }

  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));

  // Create a new thread watcher object for the given thread and activate it.
  ThreadWatcher* watcher =
      new ThreadWatcher(thread_id, thread_name, sleep_time, unresponsive_time);
  DCHECK(watcher);
  watcher->ActivateThreadWatching();
}

void ThreadWatcher::ActivateThreadWatching() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  if (active_) return;
  active_ = true;
  ping_count_ = kPingCount;
  MessageLoop::current()->PostTask(
      FROM_HERE,
      method_factory_.NewRunnableMethod(&ThreadWatcher::PostPingMessage));
}

void ThreadWatcher::DeActivateThreadWatching() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  active_ = false;
  ping_count_ = 0;
  method_factory_.RevokeAll();
}

void ThreadWatcher::WakeUp() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  // There is some user activity, PostPingMessage task of thread watcher if
  // needed.
  if (!active_) return;

  if (ping_count_ <= 0) {
    ping_count_ = kPingCount;
    PostPingMessage();
  } else {
    ping_count_ = kPingCount;
  }
}

void ThreadWatcher::PostPingMessage() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  // If we have stopped watching or if the user is idle, then stop sending
  // ping messages.
  if (!active_ || ping_count_ <= 0)
    return;

  // Save the current time when we have sent ping message.
  ping_time_ = base::TimeTicks::Now();

  // Send a ping message to the watched thread.
  Task* callback_task = method_factory_.NewRunnableMethod(
      &ThreadWatcher::OnPongMessage, ping_sequence_number_);
  if (BrowserThread::PostTask(
          thread_id(),
          FROM_HERE,
          NewRunnableFunction(
              &ThreadWatcher::OnPingMessage, thread_id_, callback_task))) {
      // Post a task to check the responsiveness of watched thread.
      MessageLoop::current()->PostDelayedTask(
          FROM_HERE,
          method_factory_.NewRunnableMethod(
              &ThreadWatcher::OnCheckResponsiveness, ping_sequence_number_),
          unresponsive_time_.InMilliseconds());
  } else {
    // Watched thread might have gone away, stop watching it.
    delete callback_task;
    DeActivateThreadWatching();
  }
}

void ThreadWatcher::OnPongMessage(uint64 ping_sequence_number) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  // Record watched thread's response time.
  base::TimeDelta response_time = base::TimeTicks::Now() - ping_time_;
  histogram_->AddTime(response_time);

  // Check if there are any extra pings in flight.
  DCHECK_EQ(ping_sequence_number_, ping_sequence_number);
  if (ping_sequence_number_ != ping_sequence_number)
    return;

  // Increment sequence number for the next ping message to indicate watched
  // thread is responsive.
  ++ping_sequence_number_;

  // If we have stopped watching or if the user is idle, then stop sending
  // ping messages.
  if (!active_ || --ping_count_ <= 0)
    return;

  MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      method_factory_.NewRunnableMethod(&ThreadWatcher::PostPingMessage),
      sleep_time_.InMilliseconds());
}

bool ThreadWatcher::OnCheckResponsiveness(uint64 ping_sequence_number) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  // If we have stopped watching then consider thread as responding.
  if (!active_)
    return true;
  // If the latest ping_sequence_number_ is not same as the ping_sequence_number
  // that is passed in, then we can assume OnPongMessage was called.
  // OnPongMessage increments ping_sequence_number_.
  if (ping_sequence_number_ != ping_sequence_number)
    return true;
  return false;
}

void ThreadWatcher::Initialize() {
  ThreadWatcherList::Register(this);
  histogram_ = base::Histogram::FactoryTimeGet(
      "ThreadWatcher.ResponseTime." + thread_name_,
      base::TimeDelta::FromMilliseconds(1),
      base::TimeDelta::FromSeconds(100), 50,
      base::Histogram::kUmaTargetedHistogramFlag);
}

// static
void ThreadWatcher::OnPingMessage(const BrowserThread::ID thread_id,
                                  Task* callback_task) {
  // This method is called on watched thread.
  DCHECK(BrowserThread::CurrentlyOn(thread_id));
  BrowserThread::PostTask(BrowserThread::WATCHDOG, FROM_HERE, callback_task);
}

//------------------------------------------------------------------------------
// ThreadWatcherList methods and members.

// static
ThreadWatcherList* ThreadWatcherList::global_ = NULL;

ThreadWatcherList::ThreadWatcherList()
    : last_wakeup_time_(base::TimeTicks::Now()) {
  // Assert we are not running on WATCHDOG thread. Would be ideal to assert we
  // are on UI thread, but Unit tests are not running on UI thread.
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  DCHECK(!global_);
  global_ = this;
  // Register Notifications observer.
#if !defined(OS_MACOSX)
  MetricsService::SetupNotifications(&registrar_, this);
#endif
}

ThreadWatcherList::~ThreadWatcherList() {
  base::AutoLock auto_lock(lock_);
  while (!registered_.empty()) {
    RegistrationList::iterator it = registered_.begin();
    delete it->second;
    registered_.erase(it->first);
  }
  DCHECK(this == global_);
  global_ = NULL;
}

// static
void ThreadWatcherList::Register(ThreadWatcher* watcher) {
  DCHECK(global_);
  base::AutoLock auto_lock(global_->lock_);
  DCHECK(!global_->PreLockedFind(watcher->thread_id()));
  global_->registered_[watcher->thread_id()] = watcher;
}

// static
void ThreadWatcherList::StopWatchingAll() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!global_)
    return;
  base::AutoLock auto_lock(global_->lock_);
  for (RegistrationList::iterator it = global_->registered_.begin();
       global_->registered_.end() != it;
       ++it)
    BrowserThread::PostTask(
        BrowserThread::WATCHDOG,
        FROM_HERE,
        NewRunnableMethod(
            it->second, &ThreadWatcher::DeActivateThreadWatching));
}

// static
void ThreadWatcherList::RemoveNotifications() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!global_)
    return;
  base::AutoLock auto_lock(global_->lock_);
#if !defined(OS_MACOSX)
  global_->registrar_.RemoveAll();
#endif
}

void ThreadWatcherList::Observe(NotificationType type,
                                const NotificationSource& source,
                                const NotificationDetails& details) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // There is some user activity, see if thread watchers are to be awakened.
  bool need_to_awaken = false;
  base::TimeTicks now = base::TimeTicks::Now();
  {
    base::AutoLock lock(lock_);
    if (now - last_wakeup_time_ > base::TimeDelta::FromSeconds(2)) {
      need_to_awaken = true;
      last_wakeup_time_ = now;
    }
  }
  if (need_to_awaken)
    BrowserThread::PostTask(
        BrowserThread::WATCHDOG,
        FROM_HERE,
        NewRunnableMethod(this, &ThreadWatcherList::WakeUpAll));
}

void ThreadWatcherList::WakeUpAll() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  base::AutoLock auto_lock(lock_);
  for (RegistrationList::iterator it = global_->registered_.begin();
       global_->registered_.end() != it;
       ++it)
    it->second->WakeUp();
}

// static
ThreadWatcher* ThreadWatcherList::Find(const BrowserThread::ID thread_id) {
  DCHECK(global_);
  base::AutoLock auto_lock(global_->lock_);
  return global_->PreLockedFind(thread_id);
}

ThreadWatcher* ThreadWatcherList::PreLockedFind(
    const BrowserThread::ID thread_id) {
  RegistrationList::iterator it = registered_.find(thread_id);
  if (registered_.end() == it)
    return NULL;
  return it->second;
}

//------------------------------------------------------------------------------
// WatchDogThread methods and members.

// The WatchDogThread object must outlive any tasks posted to the IO thread
// before the Quit task.
DISABLE_RUNNABLE_METHOD_REFCOUNT(WatchDogThread);

WatchDogThread::WatchDogThread()
    : BrowserProcessSubThread(BrowserThread::WATCHDOG) {
}

WatchDogThread::~WatchDogThread() {
  // Remove all notifications for all watched threads.
  ThreadWatcherList::RemoveNotifications();
  // We cannot rely on our base class to stop the thread since we want our
  // CleanUp function to run.
  Stop();
}

void WatchDogThread::Init() {
  // This thread shouldn't be allowed to perform any blocking disk I/O.
  base::ThreadRestrictions::SetIOAllowed(false);

  BrowserProcessSubThread::Init();

#if !defined(OS_MACOSX)
  const base::TimeDelta kSleepTime = base::TimeDelta::FromSeconds(5);
  const base::TimeDelta kUnresponsiveTime = base::TimeDelta::FromSeconds(10);
  ThreadWatcher::StartWatching(BrowserThread::UI, "UI", kSleepTime,
                               kUnresponsiveTime);
  ThreadWatcher::StartWatching(BrowserThread::IO, "IO", kSleepTime,
                               kUnresponsiveTime);
  ThreadWatcher::StartWatching(BrowserThread::DB, "DB", kSleepTime,
                               kUnresponsiveTime);
  ThreadWatcher::StartWatching(BrowserThread::FILE, "FILE", kSleepTime,
                               kUnresponsiveTime);
  ThreadWatcher::StartWatching(BrowserThread::CACHE, "CACHE", kSleepTime,
                               kUnresponsiveTime);
#endif
}
<commit_msg>Thread Hang detector - enable it for Windows only and ifdef'ed out for Mac and Linux.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/metrics/thread_watcher.h"
#include "chrome/common/notification_service.h"

// static
const int ThreadWatcher::kPingCount = 3;

//------------------------------------------------------------------------------
// ThreadWatcher methods and members.

ThreadWatcher::ThreadWatcher(const BrowserThread::ID thread_id,
                             const std::string& thread_name,
                             const base::TimeDelta& sleep_time,
                             const base::TimeDelta& unresponsive_time)
    : thread_id_(thread_id),
      thread_name_(thread_name),
      sleep_time_(sleep_time),
      unresponsive_time_(unresponsive_time),
      ping_time_(base::TimeTicks::Now()),
      ping_sequence_number_(0),
      active_(false),
      ping_count_(kPingCount),
      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
  Initialize();
}

ThreadWatcher::~ThreadWatcher() {}

// static
void ThreadWatcher::StartWatching(const BrowserThread::ID thread_id,
                                  const std::string& thread_name,
                                  const base::TimeDelta& sleep_time,
                                  const base::TimeDelta& unresponsive_time) {
  DCHECK_GE(sleep_time.InMilliseconds(), 0);
  DCHECK_GE(unresponsive_time.InMilliseconds(), sleep_time.InMilliseconds());

  // If we are not on WATCHDOG thread, then post a task to call StartWatching on
  // WATCHDOG thread.
  if (!BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG)) {
    BrowserThread::PostTask(
        BrowserThread::WATCHDOG,
        FROM_HERE,
        NewRunnableFunction(
            &ThreadWatcher::StartWatching,
            thread_id, thread_name, sleep_time, unresponsive_time));
    return;
  }

  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));

  // Create a new thread watcher object for the given thread and activate it.
  ThreadWatcher* watcher =
      new ThreadWatcher(thread_id, thread_name, sleep_time, unresponsive_time);
  DCHECK(watcher);
  watcher->ActivateThreadWatching();
}

void ThreadWatcher::ActivateThreadWatching() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  if (active_) return;
  active_ = true;
  ping_count_ = kPingCount;
  MessageLoop::current()->PostTask(
      FROM_HERE,
      method_factory_.NewRunnableMethod(&ThreadWatcher::PostPingMessage));
}

void ThreadWatcher::DeActivateThreadWatching() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  active_ = false;
  ping_count_ = 0;
  method_factory_.RevokeAll();
}

void ThreadWatcher::WakeUp() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  // There is some user activity, PostPingMessage task of thread watcher if
  // needed.
  if (!active_) return;

  if (ping_count_ <= 0) {
    ping_count_ = kPingCount;
    PostPingMessage();
  } else {
    ping_count_ = kPingCount;
  }
}

void ThreadWatcher::PostPingMessage() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  // If we have stopped watching or if the user is idle, then stop sending
  // ping messages.
  if (!active_ || ping_count_ <= 0)
    return;

  // Save the current time when we have sent ping message.
  ping_time_ = base::TimeTicks::Now();

  // Send a ping message to the watched thread.
  Task* callback_task = method_factory_.NewRunnableMethod(
      &ThreadWatcher::OnPongMessage, ping_sequence_number_);
  if (BrowserThread::PostTask(
          thread_id(),
          FROM_HERE,
          NewRunnableFunction(
              &ThreadWatcher::OnPingMessage, thread_id_, callback_task))) {
      // Post a task to check the responsiveness of watched thread.
      MessageLoop::current()->PostDelayedTask(
          FROM_HERE,
          method_factory_.NewRunnableMethod(
              &ThreadWatcher::OnCheckResponsiveness, ping_sequence_number_),
          unresponsive_time_.InMilliseconds());
  } else {
    // Watched thread might have gone away, stop watching it.
    delete callback_task;
    DeActivateThreadWatching();
  }
}

void ThreadWatcher::OnPongMessage(uint64 ping_sequence_number) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  // Record watched thread's response time.
  base::TimeDelta response_time = base::TimeTicks::Now() - ping_time_;
  histogram_->AddTime(response_time);

  // Check if there are any extra pings in flight.
  DCHECK_EQ(ping_sequence_number_, ping_sequence_number);
  if (ping_sequence_number_ != ping_sequence_number)
    return;

  // Increment sequence number for the next ping message to indicate watched
  // thread is responsive.
  ++ping_sequence_number_;

  // If we have stopped watching or if the user is idle, then stop sending
  // ping messages.
  if (!active_ || --ping_count_ <= 0)
    return;

  MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      method_factory_.NewRunnableMethod(&ThreadWatcher::PostPingMessage),
      sleep_time_.InMilliseconds());
}

bool ThreadWatcher::OnCheckResponsiveness(uint64 ping_sequence_number) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  // If we have stopped watching then consider thread as responding.
  if (!active_)
    return true;
  // If the latest ping_sequence_number_ is not same as the ping_sequence_number
  // that is passed in, then we can assume OnPongMessage was called.
  // OnPongMessage increments ping_sequence_number_.
  if (ping_sequence_number_ != ping_sequence_number)
    return true;
  return false;
}

void ThreadWatcher::Initialize() {
  ThreadWatcherList::Register(this);
  histogram_ = base::Histogram::FactoryTimeGet(
      "ThreadWatcher.ResponseTime." + thread_name_,
      base::TimeDelta::FromMilliseconds(1),
      base::TimeDelta::FromSeconds(100), 50,
      base::Histogram::kUmaTargetedHistogramFlag);
}

// static
void ThreadWatcher::OnPingMessage(const BrowserThread::ID thread_id,
                                  Task* callback_task) {
  // This method is called on watched thread.
  DCHECK(BrowserThread::CurrentlyOn(thread_id));
  BrowserThread::PostTask(BrowserThread::WATCHDOG, FROM_HERE, callback_task);
}

//------------------------------------------------------------------------------
// ThreadWatcherList methods and members.

// static
ThreadWatcherList* ThreadWatcherList::global_ = NULL;

ThreadWatcherList::ThreadWatcherList()
    : last_wakeup_time_(base::TimeTicks::Now()) {
  // Assert we are not running on WATCHDOG thread. Would be ideal to assert we
  // are on UI thread, but Unit tests are not running on UI thread.
  DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  DCHECK(!global_);
  global_ = this;
  // Register Notifications observer.
#if defined(OS_WIN)
  MetricsService::SetupNotifications(&registrar_, this);
#endif
}

ThreadWatcherList::~ThreadWatcherList() {
  base::AutoLock auto_lock(lock_);
  while (!registered_.empty()) {
    RegistrationList::iterator it = registered_.begin();
    delete it->second;
    registered_.erase(it->first);
  }
  DCHECK(this == global_);
  global_ = NULL;
}

// static
void ThreadWatcherList::Register(ThreadWatcher* watcher) {
  DCHECK(global_);
  base::AutoLock auto_lock(global_->lock_);
  DCHECK(!global_->PreLockedFind(watcher->thread_id()));
  global_->registered_[watcher->thread_id()] = watcher;
}

// static
void ThreadWatcherList::StopWatchingAll() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!global_)
    return;
  base::AutoLock auto_lock(global_->lock_);
  for (RegistrationList::iterator it = global_->registered_.begin();
       global_->registered_.end() != it;
       ++it)
    BrowserThread::PostTask(
        BrowserThread::WATCHDOG,
        FROM_HERE,
        NewRunnableMethod(
            it->second, &ThreadWatcher::DeActivateThreadWatching));
}

// static
void ThreadWatcherList::RemoveNotifications() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!global_)
    return;
#if defined(OS_WIN)
  base::AutoLock auto_lock(global_->lock_);
  global_->registrar_.RemoveAll();
#endif
}

void ThreadWatcherList::Observe(NotificationType type,
                                const NotificationSource& source,
                                const NotificationDetails& details) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // There is some user activity, see if thread watchers are to be awakened.
  bool need_to_awaken = false;
  base::TimeTicks now = base::TimeTicks::Now();
  {
    base::AutoLock lock(lock_);
    if (now - last_wakeup_time_ > base::TimeDelta::FromSeconds(2)) {
      need_to_awaken = true;
      last_wakeup_time_ = now;
    }
  }
  if (need_to_awaken)
    BrowserThread::PostTask(
        BrowserThread::WATCHDOG,
        FROM_HERE,
        NewRunnableMethod(this, &ThreadWatcherList::WakeUpAll));
}

void ThreadWatcherList::WakeUpAll() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WATCHDOG));
  base::AutoLock auto_lock(lock_);
  for (RegistrationList::iterator it = global_->registered_.begin();
       global_->registered_.end() != it;
       ++it)
    it->second->WakeUp();
}

// static
ThreadWatcher* ThreadWatcherList::Find(const BrowserThread::ID thread_id) {
  DCHECK(global_);
  base::AutoLock auto_lock(global_->lock_);
  return global_->PreLockedFind(thread_id);
}

ThreadWatcher* ThreadWatcherList::PreLockedFind(
    const BrowserThread::ID thread_id) {
  RegistrationList::iterator it = registered_.find(thread_id);
  if (registered_.end() == it)
    return NULL;
  return it->second;
}

//------------------------------------------------------------------------------
// WatchDogThread methods and members.

// The WatchDogThread object must outlive any tasks posted to the IO thread
// before the Quit task.
DISABLE_RUNNABLE_METHOD_REFCOUNT(WatchDogThread);

WatchDogThread::WatchDogThread()
    : BrowserProcessSubThread(BrowserThread::WATCHDOG) {
}

WatchDogThread::~WatchDogThread() {
  // Remove all notifications for all watched threads.
  ThreadWatcherList::RemoveNotifications();
  // We cannot rely on our base class to stop the thread since we want our
  // CleanUp function to run.
  Stop();
}

void WatchDogThread::Init() {
  // This thread shouldn't be allowed to perform any blocking disk I/O.
  base::ThreadRestrictions::SetIOAllowed(false);

  BrowserProcessSubThread::Init();

#if defined(OS_WIN)
  const base::TimeDelta kSleepTime = base::TimeDelta::FromSeconds(5);
  const base::TimeDelta kUnresponsiveTime = base::TimeDelta::FromSeconds(10);
  ThreadWatcher::StartWatching(BrowserThread::UI, "UI", kSleepTime,
                               kUnresponsiveTime);
  ThreadWatcher::StartWatching(BrowserThread::IO, "IO", kSleepTime,
                               kUnresponsiveTime);
  ThreadWatcher::StartWatching(BrowserThread::DB, "DB", kSleepTime,
                               kUnresponsiveTime);
  ThreadWatcher::StartWatching(BrowserThread::FILE, "FILE", kSleepTime,
                               kUnresponsiveTime);
  ThreadWatcher::StartWatching(BrowserThread::CACHE, "CACHE", kSleepTime,
                               kUnresponsiveTime);
#endif
}
<|endoftext|>


<commit_before>#include "../../testing/testing.hpp"

#include "../bit_streams.hpp"
#include "../reader.hpp"
#include "../writer.hpp"

#include "../../base/pseudo_random.hpp"
#include "../../std/utility.hpp"
#include "../../std/vector.hpp"

namespace
{
  uint64_t GetRand64()
  {
    static PseudoRNG32 g_rng;
    uint64_t result = g_rng.Generate();
    result ^= uint64_t(g_rng.Generate()) << 32;
    return result;
  }
}

UNIT_TEST(BitStream_ReadWrite)
{
  uint32_t const NUMS_CNT = 1000;
  vector< pair<uint64_t, uint32_t> > nums;
  for (uint32_t i = 0; i < NUMS_CNT; ++i)
  {
    uint32_t numBits = GetRand64() % 57;
    uint64_t num = GetRand64() & (uint64_t(-1) >> (64 - numBits));
    nums.push_back(make_pair(num, numBits));
  }

  vector<uint8_t> encodedBits;
  {
    MemWriter< vector<uint8_t> > encodedBitsWriter(encodedBits);
    BitSink bitsSink(encodedBitsWriter);
    for (uint32_t i = 0; i < nums.size(); ++i) bitsSink.Write(nums[i].first, nums[i].second);
  }
  MemReader encodedBitsReader(encodedBits.data(), encodedBits.size());
  BitSource bitsSource(encodedBitsReader);
  for (uint32_t i = 0; i < nums.size(); ++i)
  {
    uint64_t num = bitsSource.Read(nums[i].second);
    TEST_EQUAL(num, nums[i].first, ());
  }}

<commit_msg>[coding_tests] [bit_streams] Fix a case of shift by 64 which doesn't always work correctly.<commit_after>#include "../../testing/testing.hpp"

#include "../bit_streams.hpp"
#include "../reader.hpp"
#include "../writer.hpp"

#include "../../base/pseudo_random.hpp"
#include "../../std/utility.hpp"
#include "../../std/vector.hpp"

namespace
{
  uint64_t GetRand64()
  {
    static PseudoRNG32 g_rng;
    uint64_t result = g_rng.Generate();
    result ^= uint64_t(g_rng.Generate()) << 32;
    return result;
  }
}

UNIT_TEST(BitStream_ReadWrite)
{
  uint32_t const NUMS_CNT = 1000;
  vector< pair<uint64_t, uint32_t> > nums;
  for (uint32_t i = 0; i < NUMS_CNT; ++i)
  {
    uint32_t numBits = GetRand64() % 57;
    uint64_t num = GetRand64() & (uint64_t(-1) >> (64 - numBits));
    // Right bit shift by 64 doesn't always work correctly,
    // this is a workaround.
    if (numBits == 0) num = 0;
    nums.push_back(make_pair(num, numBits));
  }

  vector<uint8_t> encodedBits;
  {
    MemWriter< vector<uint8_t> > encodedBitsWriter(encodedBits);
    BitSink bitsSink(encodedBitsWriter);
    for (uint32_t i = 0; i < nums.size(); ++i) bitsSink.Write(nums[i].first, nums[i].second);
  }
  MemReader encodedBitsReader(encodedBits.data(), encodedBits.size());
  BitSource bitsSource(encodedBitsReader);
  for (uint32_t i = 0; i < nums.size(); ++i)
  {
    uint64_t num = bitsSource.Read(nums[i].second);
    TEST_EQUAL(num, nums[i].first, ());
  }
}

<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel 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 "taskschedulerinternal.h"
#include "../math/math.h"
#include "../sys/sysinfo.h"
#include <algorithm>

namespace embree
{
  size_t TaskScheduler::g_numThreads = 0;
  __thread TaskScheduler* TaskScheduler::g_instance = nullptr;
  __thread TaskScheduler::Thread* TaskScheduler::thread_local_thread = nullptr;
  TaskScheduler::ThreadPool* TaskScheduler::threadPool = nullptr;

  template<typename Predicate, typename Body>
  __forceinline void TaskScheduler::steal_loop(Thread& thread, const Predicate& pred, const Body& body)
  {
    while (true)
    {
      /*! some rounds that yield */
      for (size_t i=0; i<32; i++)
      {
        /*! some spinning rounds */
        const size_t threadCount = thread.threadCount();
        for (size_t j=0; j<1024; j+=threadCount)
        {
          if (!pred()) return;
          if (thread.scheduler->steal_from_other_threads(thread)) {
            i=j=0;
            body();
          }
        }
        yield();
      }
    }
  }

  /*! run this task */
  __dllexport void TaskScheduler::Task::run (Thread& thread) // FIXME: avoid as many __dllexports as possible
  {
    /* try to run if not already stolen */
    if (try_switch_state(INITIALIZED,DONE))
    {
      Task* prevTask = thread.task;
      thread.task = this;
      try {
        if (thread.scheduler->cancellingException == nullptr)
          closure->execute();
      } catch (...) {
        if (thread.scheduler->cancellingException == nullptr)
          thread.scheduler->cancellingException = std::current_exception();
      }
      thread.task = prevTask;
      add_dependencies(-1);
    }

    /* steal until all dependencies have completed */
    steal_loop(thread,
               [&] () { return dependencies>0; },
               [&] () { while (thread.tasks.execute_local(thread,this)); });

    /* now signal our parent task that we are finished */
    if (parent)
      parent->add_dependencies(-1);
  }

  __dllexport bool TaskScheduler::TaskQueue::execute_local(Thread& thread, Task* parent)
  {
    /* stop if we run out of local tasks or reach the waiting task */
    if (right == 0 || &tasks[right-1] == parent)
      return false;

    /* execute task */
    size_t oldRight = right;
    tasks[right-1].run(thread);
    if (right != oldRight) {
      THROW_RUNTIME_ERROR("you have to wait for spawned subtasks");
    }

    /* pop task and closure from stack */
    right--;
    if (tasks[right].stackPtr != size_t(-1))
      stackPtr = tasks[right].stackPtr;

    /* also move left pointer */
    if (left >= right) left.store(right.load());

    return right != 0;
  }

  bool TaskScheduler::TaskQueue::steal(Thread& thread)
  {
    size_t l = left;
    if (l < right)
      l = left++;
    else
      return false;

    if (!tasks[l].try_steal(thread.tasks.tasks[thread.tasks.right]))
      return false;

    thread.tasks.right++;
    return true;
  }

  /* we steal from the left */
  size_t TaskScheduler::TaskQueue::getTaskSizeAtLeft()
  {
    if (left >= right) return 0;
    return tasks[left].N;
  }

  static MutexSys g_mutex;

  void threadPoolFunction(std::pair<TaskScheduler::ThreadPool*,size_t>* pair)
  {
    TaskScheduler::ThreadPool* pool = pair->first;
    size_t threadIndex = pair->second;
    pool->thread_loop(threadIndex);
	delete pair;
  }

  TaskScheduler::ThreadPool::ThreadPool(bool set_affinity)
    : numThreads(0), numThreadsRunning(0), set_affinity(set_affinity), running(false) {}

  __dllexport void TaskScheduler::ThreadPool::startThreads()
  {
    if (running) return;
    setNumThreads(numThreads,true);
  }

  void TaskScheduler::ThreadPool::setNumThreads(size_t newNumThreads, bool startThreads)
  {
    Lock<MutexSys> lock(g_mutex);

    if (newNumThreads == 0)
      newNumThreads = getNumberOfLogicalThreads();

    numThreads = newNumThreads;
    if (!startThreads && !running) return;
    running = true;
    size_t numThreadsActive = numThreadsRunning;

    mutex.lock();
    numThreadsRunning = newNumThreads;
    mutex.unlock();
    condition.notify_all();

    /* start new threads */
    for (size_t t=numThreadsActive; t<numThreads; t++)
    {
      if (t == 0) continue;
      auto pair = new std::pair<TaskScheduler::ThreadPool*,size_t>(this,t);
      threads.push_back(createThread((thread_func)threadPoolFunction,pair,4*1024*1024,set_affinity ? t : -1));
    }

    /* stop some threads if we reduce the number of threads */
    for (ssize_t t=numThreadsActive-1; t>=ssize_t(numThreadsRunning); t--) {
      if (t == 0) continue;
      embree::join(threads.back());
      threads.pop_back();
    }
  }

  TaskScheduler::ThreadPool::~ThreadPool()
  {
    /* leave all taskschedulers */
    mutex.lock();
    numThreadsRunning = 0;
    mutex.unlock();
    condition.notify_all();

    /* wait for threads to terminate */
    for (size_t i=0; i<threads.size(); i++)
      embree::join(threads[i]);
  }

  __dllexport void TaskScheduler::ThreadPool::add(const Ref<TaskScheduler>& scheduler)
  {
    mutex.lock();
    schedulers.push_back(scheduler);
    mutex.unlock();
    condition.notify_all();
  }

  __dllexport void TaskScheduler::ThreadPool::remove(const Ref<TaskScheduler>& scheduler)
  {
    Lock<MutexSys> lock(mutex);
    for (std::list<Ref<TaskScheduler> >::iterator it = schedulers.begin(); it != schedulers.end(); it++) {
      if (scheduler == *it) {
        schedulers.erase(it);
        return;
      }
    }
  }

  void TaskScheduler::ThreadPool::thread_loop(size_t globalThreadIndex)
  {
    while (globalThreadIndex < numThreadsRunning)
    {
      Ref<TaskScheduler> scheduler = NULL;
      ssize_t threadIndex = -1;
      {
        Lock<MutexSys> lock(mutex);
        condition.wait(mutex, [&] () { return globalThreadIndex >= numThreadsRunning || !schedulers.empty(); });
        if (globalThreadIndex >= numThreadsRunning) break;
        scheduler = schedulers.front();
        threadIndex = scheduler->allocThreadIndex();
      }
      scheduler->thread_loop(threadIndex);
    }
  }

  TaskScheduler::TaskScheduler()
    : threadCounter(0), anyTasksRunning(0), hasRootTask(false)
  {
    threadLocal.resize(2*getNumberOfLogicalThreads()); // FIXME: this has to be 2x as in the join mode the worker threads also join
    for (size_t i=0; i<threadLocal.size(); i++)
      threadLocal[i].store(nullptr);
  }

  TaskScheduler::~TaskScheduler()
  {
    assert(threadCounter == 0);
  }

  __dllexport size_t TaskScheduler::threadIndex()
  {
    Thread* thread = TaskScheduler::thread();
    if (thread) return thread->threadIndex;
    else        return 0;
  }

  __dllexport size_t TaskScheduler::threadCount() {
    return threadPool->size();
  }

  __dllexport TaskScheduler* TaskScheduler::instance()
  {
    if (g_instance == NULL) {
      g_instance = new TaskScheduler;
      g_instance->refInc();
    }
    return g_instance;
  }

  void TaskScheduler::create(size_t numThreads, bool set_affinity)
  {
    if (!threadPool) threadPool = new TaskScheduler::ThreadPool(set_affinity);
    threadPool->setNumThreads(numThreads,false);
  }

  void TaskScheduler::destroy() {
    delete threadPool; threadPool = nullptr;
  }

  __dllexport ssize_t TaskScheduler::allocThreadIndex()
  {
    size_t threadIndex = threadCounter++;
    assert(threadIndex < threadLocal.size());
    return threadIndex;
  }

  void TaskScheduler::join()
  {
    mutex.lock();
    size_t threadIndex = allocThreadIndex();
    condition.wait(mutex, [&] () { return hasRootTask.load(); });
    mutex.unlock();
    std::exception_ptr except = thread_loop(threadIndex);
    if (except != nullptr) std::rethrow_exception(except);
  }

  void TaskScheduler::reset() {
    hasRootTask = false;
  }

  void TaskScheduler::wait_for_threads(size_t threadCount)
  {
    while (threadCounter < threadCount-1)
      __pause_cpu();
  }

  __dllexport TaskScheduler::Thread* TaskScheduler::thread() {
    return thread_local_thread;
  }

  __dllexport TaskScheduler::Thread* TaskScheduler::swapThread(Thread* thread)
  {
    Thread* old = thread_local_thread;
    thread_local_thread = thread;
    return old;
  }

  __dllexport bool TaskScheduler::wait()
  {
    Thread* thread = TaskScheduler::thread();
    if (thread == nullptr) return true;
    while (thread->tasks.execute_local(*thread,thread->task)) {};
    return thread->scheduler->cancellingException == nullptr;
  }

  std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
  {
    /* allocate thread structure */
    std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
    Thread& thread = *mthread;
    threadLocal[threadIndex].store(&thread);
    Thread* oldThread = swapThread(&thread);

    /* main thread loop */
    while (anyTasksRunning)
    {
      steal_loop(thread,
                 [&] () { return anyTasksRunning > 0; },
                 [&] () {
                   anyTasksRunning++;
                   while (thread.tasks.execute_local(thread,nullptr));
                   anyTasksRunning--;
                 });
    }
    threadLocal[threadIndex].store(nullptr);
    swapThread(oldThread);

    /* remember exception to throw */
    std::exception_ptr except = nullptr;
    if (cancellingException != nullptr) except = cancellingException;

    /* wait for all threads to terminate */
    threadCounter--;
#if defined(__WIN32__)
	size_t loopIndex = 1;
#endif
#define LOOP_YIELD_THRESHOLD (4096)
	while (threadCounter > 0) {
#if defined(__WIN32__)
          if ((loopIndex % LOOP_YIELD_THRESHOLD) == 0)
            yield();
          else
            _mm_pause();
	  loopIndex++;
#else
          yield();
#endif
	}
    return except;
  }

  bool TaskScheduler::steal_from_other_threads(Thread& thread)
  {
    const size_t threadIndex = thread.threadIndex;
    const size_t threadCount = this->threadCounter;

    for (size_t i=1; i<threadCount; i++)
    {
      __pause_cpu(32);
      size_t otherThreadIndex = threadIndex+i;
      if (otherThreadIndex >= threadCount) otherThreadIndex -= threadCount;

      Thread* othread = threadLocal[otherThreadIndex].load();
      if (!othread)
        continue;

      if (othread->tasks.steal(thread))
        return true;
    }

    return false;
  }

  __dllexport void TaskScheduler::startThreads() {
    threadPool->startThreads();
  }

  __dllexport void TaskScheduler::addScheduler(const Ref<TaskScheduler>& scheduler) {
    threadPool->add(scheduler);
  }

  __dllexport void TaskScheduler::removeScheduler(const Ref<TaskScheduler>& scheduler) {
    threadPool->remove(scheduler);
  }
}
<commit_msg>update<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel 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 "taskschedulerinternal.h"
#include "../math/math.h"
#include "../sys/sysinfo.h"
#include <algorithm>

namespace embree
{
  size_t TaskScheduler::g_numThreads = 0;
  __thread TaskScheduler* TaskScheduler::g_instance = nullptr;
  __thread TaskScheduler::Thread* TaskScheduler::thread_local_thread = nullptr;
  TaskScheduler::ThreadPool* TaskScheduler::threadPool = nullptr;

  template<typename Predicate, typename Body>
  __forceinline void TaskScheduler::steal_loop(Thread& thread, const Predicate& pred, const Body& body)
  {
    while (true)
    {
      /*! some rounds that yield */
      for (size_t i=0; i<32; i++)
      {
        /*! some spinning rounds */
        const size_t threadCount = thread.threadCount();
        for (size_t j=0; j<1024; j+=threadCount)
        {
          if (!pred()) return;
          if (thread.scheduler->steal_from_other_threads(thread)) {
            i=j=0;
            body();
          }
        }
        yield();
      }
    }
  }

  /*! run this task */
  __dllexport void TaskScheduler::Task::run (Thread& thread) // FIXME: avoid as many __dllexports as possible
  {
    /* try to run if not already stolen */
    if (try_switch_state(INITIALIZED,DONE))
    {
      Task* prevTask = thread.task;
      thread.task = this;
      try {
        if (thread.scheduler->cancellingException == nullptr)
          closure->execute();
      } catch (...) {
        if (thread.scheduler->cancellingException == nullptr)
          thread.scheduler->cancellingException = std::current_exception();
      }
      thread.task = prevTask;
      add_dependencies(-1);
    }

    /* steal until all dependencies have completed */
    steal_loop(thread,
               [&] () { return dependencies>0; },
               [&] () { while (thread.tasks.execute_local(thread,this)); });

    /* now signal our parent task that we are finished */
    if (parent)
      parent->add_dependencies(-1);
  }

  __dllexport bool TaskScheduler::TaskQueue::execute_local(Thread& thread, Task* parent)
  {
    /* stop if we run out of local tasks or reach the waiting task */
    if (right == 0 || &tasks[right-1] == parent)
      return false;

    /* execute task */
    size_t oldRight = right;
    tasks[right-1].run(thread);
    if (right != oldRight) {
      THROW_RUNTIME_ERROR("you have to wait for spawned subtasks");
    }

    /* pop task and closure from stack */
    right--;
    if (tasks[right].stackPtr != size_t(-1))
      stackPtr = tasks[right].stackPtr;

    /* also move left pointer */
    if (left >= right) left.store(right.load());

    return right != 0;
  }

  bool TaskScheduler::TaskQueue::steal(Thread& thread)
  {
    size_t l = left;
    if (l < right)
      l = left++;
    else
      return false;

    if (!tasks[l].try_steal(thread.tasks.tasks[thread.tasks.right]))
      return false;

    thread.tasks.right++;
    return true;
  }

  /* we steal from the left */
  size_t TaskScheduler::TaskQueue::getTaskSizeAtLeft()
  {
    if (left >= right) return 0;
    return tasks[left].N;
  }

  static MutexSys g_mutex;

  void threadPoolFunction(std::pair<TaskScheduler::ThreadPool*,size_t>* pair)
  {
    TaskScheduler::ThreadPool* pool = pair->first;
    size_t threadIndex = pair->second;
    delete pair;
    pool->thread_loop(threadIndex);
  }

  TaskScheduler::ThreadPool::ThreadPool(bool set_affinity)
    : numThreads(0), numThreadsRunning(0), set_affinity(set_affinity), running(false) {}

  __dllexport void TaskScheduler::ThreadPool::startThreads()
  {
    if (running) return;
    setNumThreads(numThreads,true);
  }

  void TaskScheduler::ThreadPool::setNumThreads(size_t newNumThreads, bool startThreads)
  {
    Lock<MutexSys> lock(g_mutex);

    if (newNumThreads == 0)
      newNumThreads = getNumberOfLogicalThreads();

    numThreads = newNumThreads;
    if (!startThreads && !running) return;
    running = true;
    size_t numThreadsActive = numThreadsRunning;

    mutex.lock();
    numThreadsRunning = newNumThreads;
    mutex.unlock();
    condition.notify_all();

    /* start new threads */
    for (size_t t=numThreadsActive; t<numThreads; t++)
    {
      if (t == 0) continue;
      auto pair = new std::pair<TaskScheduler::ThreadPool*,size_t>(this,t);
      threads.push_back(createThread((thread_func)threadPoolFunction,pair,4*1024*1024,set_affinity ? t : -1));
    }

    /* stop some threads if we reduce the number of threads */
    for (ssize_t t=numThreadsActive-1; t>=ssize_t(numThreadsRunning); t--) {
      if (t == 0) continue;
      embree::join(threads.back());
      threads.pop_back();
    }
  }

  TaskScheduler::ThreadPool::~ThreadPool()
  {
    /* leave all taskschedulers */
    mutex.lock();
    numThreadsRunning = 0;
    mutex.unlock();
    condition.notify_all();

    /* wait for threads to terminate */
    for (size_t i=0; i<threads.size(); i++)
      embree::join(threads[i]);
  }

  __dllexport void TaskScheduler::ThreadPool::add(const Ref<TaskScheduler>& scheduler)
  {
    mutex.lock();
    schedulers.push_back(scheduler);
    mutex.unlock();
    condition.notify_all();
  }

  __dllexport void TaskScheduler::ThreadPool::remove(const Ref<TaskScheduler>& scheduler)
  {
    Lock<MutexSys> lock(mutex);
    for (std::list<Ref<TaskScheduler> >::iterator it = schedulers.begin(); it != schedulers.end(); it++) {
      if (scheduler == *it) {
        schedulers.erase(it);
        return;
      }
    }
  }

  void TaskScheduler::ThreadPool::thread_loop(size_t globalThreadIndex)
  {
    while (globalThreadIndex < numThreadsRunning)
    {
      Ref<TaskScheduler> scheduler = NULL;
      ssize_t threadIndex = -1;
      {
        Lock<MutexSys> lock(mutex);
        condition.wait(mutex, [&] () { return globalThreadIndex >= numThreadsRunning || !schedulers.empty(); });
        if (globalThreadIndex >= numThreadsRunning) break;
        scheduler = schedulers.front();
        threadIndex = scheduler->allocThreadIndex();
      }
      scheduler->thread_loop(threadIndex);
    }
  }

  TaskScheduler::TaskScheduler()
    : threadCounter(0), anyTasksRunning(0), hasRootTask(false)
  {
    threadLocal.resize(2*getNumberOfLogicalThreads()); // FIXME: this has to be 2x as in the join mode the worker threads also join
    for (size_t i=0; i<threadLocal.size(); i++)
      threadLocal[i].store(nullptr);
  }

  TaskScheduler::~TaskScheduler()
  {
    assert(threadCounter == 0);
  }

  __dllexport size_t TaskScheduler::threadIndex()
  {
    Thread* thread = TaskScheduler::thread();
    if (thread) return thread->threadIndex;
    else        return 0;
  }

  __dllexport size_t TaskScheduler::threadCount() {
    return threadPool->size();
  }

  __dllexport TaskScheduler* TaskScheduler::instance()
  {
    if (g_instance == NULL) {
      g_instance = new TaskScheduler;
      g_instance->refInc();
    }
    return g_instance;
  }

  void TaskScheduler::create(size_t numThreads, bool set_affinity)
  {
    if (!threadPool) threadPool = new TaskScheduler::ThreadPool(set_affinity);
    threadPool->setNumThreads(numThreads,false);
  }

  void TaskScheduler::destroy() {
    delete threadPool; threadPool = nullptr;
  }

  __dllexport ssize_t TaskScheduler::allocThreadIndex()
  {
    size_t threadIndex = threadCounter++;
    assert(threadIndex < threadLocal.size());
    return threadIndex;
  }

  void TaskScheduler::join()
  {
    mutex.lock();
    size_t threadIndex = allocThreadIndex();
    condition.wait(mutex, [&] () { return hasRootTask.load(); });
    mutex.unlock();
    std::exception_ptr except = thread_loop(threadIndex);
    if (except != nullptr) std::rethrow_exception(except);
  }

  void TaskScheduler::reset() {
    hasRootTask = false;
  }

  void TaskScheduler::wait_for_threads(size_t threadCount)
  {
    while (threadCounter < threadCount-1)
      __pause_cpu();
  }

  __dllexport TaskScheduler::Thread* TaskScheduler::thread() {
    return thread_local_thread;
  }

  __dllexport TaskScheduler::Thread* TaskScheduler::swapThread(Thread* thread)
  {
    Thread* old = thread_local_thread;
    thread_local_thread = thread;
    return old;
  }

  __dllexport bool TaskScheduler::wait()
  {
    Thread* thread = TaskScheduler::thread();
    if (thread == nullptr) return true;
    while (thread->tasks.execute_local(*thread,thread->task)) {};
    return thread->scheduler->cancellingException == nullptr;
  }

  std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex)
  {
    /* allocate thread structure */
    std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation
    Thread& thread = *mthread;
    threadLocal[threadIndex].store(&thread);
    Thread* oldThread = swapThread(&thread);

    /* main thread loop */
    while (anyTasksRunning)
    {
      steal_loop(thread,
                 [&] () { return anyTasksRunning > 0; },
                 [&] () {
                   anyTasksRunning++;
                   while (thread.tasks.execute_local(thread,nullptr));
                   anyTasksRunning--;
                 });
    }
    threadLocal[threadIndex].store(nullptr);
    swapThread(oldThread);

    /* remember exception to throw */
    std::exception_ptr except = nullptr;
    if (cancellingException != nullptr) except = cancellingException;

    /* wait for all threads to terminate */
    threadCounter--;
#if defined(__WIN32__)
	size_t loopIndex = 1;
#endif
#define LOOP_YIELD_THRESHOLD (4096)
	while (threadCounter > 0) {
#if defined(__WIN32__)
          if ((loopIndex % LOOP_YIELD_THRESHOLD) == 0)
            yield();
          else
            _mm_pause();
	  loopIndex++;
#else
          yield();
#endif
	}
    return except;
  }

  bool TaskScheduler::steal_from_other_threads(Thread& thread)
  {
    const size_t threadIndex = thread.threadIndex;
    const size_t threadCount = this->threadCounter;

    for (size_t i=1; i<threadCount; i++)
    {
      __pause_cpu(32);
      size_t otherThreadIndex = threadIndex+i;
      if (otherThreadIndex >= threadCount) otherThreadIndex -= threadCount;

      Thread* othread = threadLocal[otherThreadIndex].load();
      if (!othread)
        continue;

      if (othread->tasks.steal(thread))
        return true;
    }

    return false;
  }

  __dllexport void TaskScheduler::startThreads() {
    threadPool->startThreads();
  }

  __dllexport void TaskScheduler::addScheduler(const Ref<TaskScheduler>& scheduler) {
    threadPool->add(scheduler);
  }

  __dllexport void TaskScheduler::removeScheduler(const Ref<TaskScheduler>& scheduler) {
    threadPool->remove(scheduler);
  }
}
<|endoftext|>


<commit_before>/*
 * test.cpp
 *
 *  Created on: Nov 19, 2014
 *      Author: matheus
 */

#include <cstdlib>
#include <ctime>

#include "ConcreteGraph.hpp"
#include "Helpers.hpp"
#include "GraphAlgorithms.hpp"
#include "ThreadManager.hpp"

using namespace std;
using namespace graph;

static int n_threads = 1;
static int delta = 1;
static int max_weight = 1000;
static int order = 1000;

static inline void generateAndRun() {
  IntArrayGraphMapNeighbourHood G;

  // [2, max_order] vertices, weights in [1, max_weight]
  generateGraph(G, order, max_weight);

  IntAllPairsShortestPaths res3(G, IntParallelDeltaStepping());
}

void test(int argc, char** argv) {
  srand(time(nullptr));
  if (argc >= 2) {
    sscanf(argv[1], "%d", &n_threads);
  }
  if (argc >= 3) {
    sscanf(argv[2], "%d", &delta);
  }
  if (argc >= 4) {
    sscanf(argv[3], "%d", &max_weight);
  }
  if (argc >= 5) {
    sscanf(argv[4], "%d", &order);
  }
  DeltaStepping::delta(&delta);
  DeltaStepping::initRelaxations();
  ThreadManager::init(n_threads);

  generateAndRun();

  printf("relaxations: %lu\n", DeltaStepping::relaxations());

  ThreadManager::close();
  DeltaStepping::closeRelaxations();
}
<commit_msg>Creating a basic test<commit_after>/*
 * test.cpp
 *
 *  Created on: Nov 19, 2014
 *      Author: matheus
 */

#include <cstdlib>
#include <ctime>

#include "ConcreteGraph.hpp"
#include "Helpers.hpp"
#include "GraphAlgorithms.hpp"
#include "ThreadManager.hpp"

using namespace std;
using namespace graph;

static int n_threads = 1;
static int delta = 1;
static int max_weight = 100;
static int order = 100;

static inline void generateAndRun() {
  IntArrayGraphMapNeighbourHood G;

  // [2, max_order] vertices, weights in [1, max_weight]
  generateGraph(G, order, max_weight);

  IntAllPairsShortestPaths res3(G, IntParallelDeltaStepping());
}

void test(int argc, char** argv) {
  srand(time(nullptr));
  if (argc >= 2) {
    sscanf(argv[1], "%d", &n_threads);
  }
  if (argc >= 3) {
    sscanf(argv[2], "%d", &delta);
  }
  if (argc >= 4) {
    sscanf(argv[3], "%d", &max_weight);
  }
  if (argc >= 5) {
    sscanf(argv[4], "%d", &order);
  }
  DeltaStepping::delta(&delta);
  DeltaStepping::initRelaxations();
  ThreadManager::init(n_threads);

  generateAndRun();

  printf("relaxations: %lu\n", DeltaStepping::relaxations());

  ThreadManager::close();
  DeltaStepping::closeRelaxations();
}
<|endoftext|>


<commit_before>
#ifdef _WIN32
#define _UNICODE 1
#define UNICODE 1
#endif
#define BOOST_TEST_MODULE SlipRock module
#ifdef _MSC_VER
#include <boost/test/included/unit_test.hpp>
#else
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#endif

#include "../include/sliprock.h"
#include "sliprock_internals.h"
#include "stringbuf.h"
#include <csignal>
#include <exception>
#include <mutex>
#include <stdexcept>
#include <stdlib.h>
#include <thread>
#include <type_traits>

#ifdef _WIN32
#define address pipename
#include <windows.h>
#endif
#ifndef BOOST_TEST
#define BOOST_TEST BOOST_CHECK
#endif

#ifndef _WIN32
typedef int HANDLE;
#include <pthread.h>
#define INVALID_HANDLE_VALUE (-1)
#endif
static uint32_t sliprock_getpid(void) {
#ifdef _WIN32
  return GetCurrentProcessId();
#else
  return (uint32_t)getpid();
#endif
}
struct set_on_close {
  set_on_close(std::mutex &m, bool &b) : boolean(b), mut(m) {}
  ~set_on_close() {
    std::unique_lock<std::mutex> locker{mut};
    boolean = true;
  }

private:
  bool &boolean;
  std::mutex &mut;
};
template <size_t size>
bool client(char (&buf)[size], SliprockConnection *con, bool &finished,
            std::mutex &mutex) {
  set_on_close closer(mutex, finished);
  char buf2[size + 1] = {0};
  bool read_succeeded = false;
  SliprockHandle fd_ = (SliprockHandle)INVALID_HANDLE_VALUE;
#ifndef _WIN32
  BOOST_TEST(system("ls -a ~/.sliprock") == 0);
#endif
  SliprockReceiver *receiver;
  int x = sliprock_open("dummy_valr", sizeof("dummy_val") - 1,
                        sliprock_getpid(), &receiver);
  BOOST_TEST(x == 0);
  BOOST_REQUIRE(x == 0);
  MADE_IT;
  x = sliprock_connect(receiver, &fd_);
  BOOST_TEST(x == 0);
  BOOST_REQUIRE(x == 0);
  MADE_IT;
  HANDLE fd = (HANDLE)fd_;
#ifdef _WIN32
  DWORD read;
  BOOST_TEST(0 != ReadFile(fd, buf2, sizeof buf, &read, nullptr));
  BOOST_TEST(read == sizeof buf);
  BOOST_TEST(0 != WriteFile(fd, buf2, sizeof buf, &read, nullptr));
  BOOST_TEST(read == sizeof buf);
  FlushFileBuffers(fd);
#else
  if (fd >= 0) {
    BOOST_TEST(sizeof buf == read(fd, buf2, sizeof buf));
    BOOST_TEST(sizeof buf == write(fd, buf2, sizeof buf));
  }
#endif
  // static_assert(sizeof buf2 == sizeof buf, "Buffer size mismatch");
  static_assert(sizeof con->address == sizeof receiver->sock,
                "Connection size mismatch");
  BOOST_TEST(memcmp(&buf2[0], &buf[0], sizeof buf) == 0);
  fwrite(buf, 1, sizeof buf, stderr);
  fwrite(buf2, 1, sizeof buf2, stderr);
#ifndef _WIN32
  BOOST_TEST((int)fd > -1);
#endif
  read_succeeded = true;
  BOOST_TEST(0 == memcmp(reinterpret_cast<void *>(&receiver->sock),
                         reinterpret_cast<void *>(&con->address),
                         sizeof con->address));
  BOOST_TEST(read_succeeded == true);
  BOOST_TEST(receiver != static_cast<SliprockReceiver *>(nullptr));
#ifndef _WIN32
  BOOST_TEST(close(fd) == 0);
#else
  BOOST_TEST(CloseHandle(fd) != 0);
#endif
  sliprock_close_receiver(receiver);
  return read_succeeded;
}

template <size_t n>
bool server(char (&buf)[n], SliprockConnection *con, bool &finished,
            std::mutex &mutex) {
  set_on_close closer(mutex, finished);
  MADE_IT;
  SliprockHandle handle_;
  int err = sliprock_accept(con, &handle_);
  if (err != 0) {
    fprintf(stderr, "error code %d\n", err);
    return false;
  }
  auto handle = (HANDLE)handle_;
  MADE_IT;
  if (handle == INVALID_HANDLE_VALUE)
    return false;
  MADE_IT;
  char buf3[sizeof buf];
#ifndef _WIN32
  if (write(handle, buf, sizeof buf) != sizeof buf)
    return false;
  MADE_IT;
  if (read(handle, buf3, sizeof buf) != sizeof buf)
    return false;
  MADE_IT;
  if (close(handle))
    return false;
  MADE_IT;
#else
  DWORD written;
  MADE_IT;
  if (WriteFile(handle, buf, sizeof buf, &written, NULL) == 0)
    return false;
  if (!FlushFileBuffers(handle))
    return false;
  MADE_IT;
  if (written != sizeof buf3)
    return false;
  MADE_IT;
  if (ReadFile(handle, buf3, sizeof buf3, &written, NULL) == 0)
    return false;
  if (!CloseHandle(handle))
    return false;
  MADE_IT;
#endif
  bool x = !memcmp(buf3, buf, sizeof buf);
  finished = true;
  return x;
}
#ifndef _WIN32
static void donothing(int _) {
  (void)_;
  return;
}
static_assert(std::is_same<std::thread::native_handle_type, pthread_t>(),
              "Mismatched native handle type!");
#elif 0
static_assert(std::is_same<std::thread::native_handle_type, HANDLE>(),
              "Mismatched native handle type!");
#endif
// Interrupt a thread IF read_done is true, ensuring that lock is held
// when reading its value.
static void interrupt_thread(std::mutex &lock, const bool &read_done,
                             std::thread &thread) {
  std::unique_lock<std::mutex> locker(lock);
  if (!read_done) {
#ifndef _WIN32
    static_assert(std::is_same<std::thread::native_handle_type, pthread_t>::value,
                  "Bad native handle type");
    pthread_kill(thread.native_handle(), SIGPIPE);
#elif _MSC_VER
    static_assert(std::is_same<std::thread::native_handle_type, HANDLE>::value,
                  "Bad native handle type");
    CancelSynchronousIo(thread.native_handle());
#else
    (void)thread;
#endif
  }
}
BOOST_AUTO_TEST_CASE(can_create_connection) {
#ifndef _WIN32
  struct sigaction sigact;
  memset(&sigact, 0, sizeof sigact);
  sigact.sa_handler = donothing;
  sigemptyset(&sigact.sa_mask);
  sigaddset(&sigact.sa_mask, SIGPIPE);
  sigaction(SIGPIPE, &sigact, nullptr);
  BOOST_TEST(system("rm -rf -- \"$HOME/.sliprock\" /tmp/sliprock.*") == 0);
#endif
  SliprockConnection *con = nullptr;
  int x = sliprock_socket("dummy_val", sizeof("dummy_val") - 1, &con);
  BOOST_TEST(x == 0);
  BOOST_REQUIRE(x == 0);

  std::mutex lock, lock2;
  bool read_done = false, write_done = false;
  char buf[] = "Test message!\n";
  bool write_succeeded = false, read_succeeded = false;
  std::thread thread([&]() {
    if (!(read_succeeded = server(buf, con, read_done, lock2)))
      perror("sliprock_server");
  });
  std::thread thread2(
      [&]() { write_succeeded = client(buf, con, write_done, lock); });
  auto interrupter = std::thread{[&]() {
#ifndef _WIN32
    struct timespec q = {1, 0};
    nanosleep(&q, nullptr);
#else
    Sleep(100000);
#endif
    sliprock_trace("Interrupting thread\n");
    interrupt_thread(lock2, read_done, thread);
    interrupt_thread(lock, write_done, thread2);
  }};
  thread.join();
  thread2.join();
#ifdef _WIN32
  interrupter.detach();
#else
  interrupter.join();
#endif
  BOOST_TEST(write_succeeded);
  BOOST_TEST(read_succeeded);

  sliprock_close(con);
}
// BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Add logging of sleep call<commit_after>
#ifdef _WIN32
#define _UNICODE 1
#define UNICODE 1
#endif
#define BOOST_TEST_MODULE SlipRock module
#ifdef _MSC_VER
#include <boost/test/included/unit_test.hpp>
#else
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#endif

#include "../include/sliprock.h"
#include "sliprock_internals.h"
#include "stringbuf.h"
#include <csignal>
#include <exception>
#include <mutex>
#include <stdexcept>
#include <stdlib.h>
#include <thread>
#include <type_traits>

#ifdef _WIN32
#define address pipename
#include <windows.h>
#endif
#ifndef BOOST_TEST
#define BOOST_TEST BOOST_CHECK
#endif

#ifndef _WIN32
typedef int HANDLE;
#include <pthread.h>
#define INVALID_HANDLE_VALUE (-1)
#endif
static uint32_t sliprock_getpid(void) {
#ifdef _WIN32
  return GetCurrentProcessId();
#else
  return (uint32_t)getpid();
#endif
}
struct set_on_close {
  set_on_close(std::mutex &m, bool &b) : boolean(b), mut(m) {}
  ~set_on_close() {
    std::unique_lock<std::mutex> locker{mut};
    boolean = true;
  }

private:
  bool &boolean;
  std::mutex &mut;
};
template <size_t size>
bool client(char (&buf)[size], SliprockConnection *con, bool &finished,
            std::mutex &mutex) {
  set_on_close closer(mutex, finished);
  char buf2[size + 1] = {0};
  bool read_succeeded = false;
  SliprockHandle fd_ = (SliprockHandle)INVALID_HANDLE_VALUE;
#ifndef _WIN32
  BOOST_TEST(system("ls -a ~/.sliprock") == 0);
#endif
  SliprockReceiver *receiver;
  int x = sliprock_open("dummy_valr", sizeof("dummy_val") - 1,
                        sliprock_getpid(), &receiver);
  BOOST_TEST(x == 0);
  BOOST_REQUIRE(x == 0);
  MADE_IT;
  x = sliprock_connect(receiver, &fd_);
  BOOST_TEST(x == 0);
  BOOST_REQUIRE(x == 0);
  MADE_IT;
  HANDLE fd = (HANDLE)fd_;
#ifdef _WIN32
  DWORD read;
  BOOST_TEST(0 != ReadFile(fd, buf2, sizeof buf, &read, nullptr));
  BOOST_TEST(read == sizeof buf);
  BOOST_TEST(0 != WriteFile(fd, buf2, sizeof buf, &read, nullptr));
  BOOST_TEST(read == sizeof buf);
  FlushFileBuffers(fd);
#else
  if (fd >= 0) {
    BOOST_TEST(sizeof buf == read(fd, buf2, sizeof buf));
    BOOST_TEST(sizeof buf == write(fd, buf2, sizeof buf));
  }
#endif
  // static_assert(sizeof buf2 == sizeof buf, "Buffer size mismatch");
  static_assert(sizeof con->address == sizeof receiver->sock,
                "Connection size mismatch");
  BOOST_TEST(memcmp(&buf2[0], &buf[0], sizeof buf) == 0);
  fwrite(buf, 1, sizeof buf, stderr);
  fwrite(buf2, 1, sizeof buf2, stderr);
#ifndef _WIN32
  BOOST_TEST((int)fd > -1);
#endif
  read_succeeded = true;
  BOOST_TEST(0 == memcmp(reinterpret_cast<void *>(&receiver->sock),
                         reinterpret_cast<void *>(&con->address),
                         sizeof con->address));
  BOOST_TEST(read_succeeded == true);
  BOOST_TEST(receiver != static_cast<SliprockReceiver *>(nullptr));
#ifndef _WIN32
  BOOST_TEST(close(fd) == 0);
#else
  BOOST_TEST(CloseHandle(fd) != 0);
#endif
  sliprock_close_receiver(receiver);
  return read_succeeded;
}

template <size_t n>
bool server(char (&buf)[n], SliprockConnection *con, bool &finished,
            std::mutex &mutex) {
  set_on_close closer(mutex, finished);
  MADE_IT;
  SliprockHandle handle_;
  int err = sliprock_accept(con, &handle_);
  if (err != 0) {
    fprintf(stderr, "error code %d\n", err);
    return false;
  }
  auto handle = (HANDLE)handle_;
  MADE_IT;
  if (handle == INVALID_HANDLE_VALUE)
    return false;
  MADE_IT;
  char buf3[sizeof buf];
#ifndef _WIN32
  if (write(handle, buf, sizeof buf) != sizeof buf)
    return false;
  MADE_IT;
  if (read(handle, buf3, sizeof buf) != sizeof buf)
    return false;
  MADE_IT;
  if (close(handle))
    return false;
  MADE_IT;
#else
  DWORD written;
  MADE_IT;
  if (WriteFile(handle, buf, sizeof buf, &written, NULL) == 0)
    return false;
  if (!FlushFileBuffers(handle))
    return false;
  MADE_IT;
  if (written != sizeof buf3)
    return false;
  MADE_IT;
  if (ReadFile(handle, buf3, sizeof buf3, &written, NULL) == 0)
    return false;
  if (!CloseHandle(handle))
    return false;
  MADE_IT;
#endif
  bool x = !memcmp(buf3, buf, sizeof buf);
  finished = true;
  return x;
}
#ifndef _WIN32
static void donothing(int _) {
  (void)_;
  return;
}
static_assert(std::is_same<std::thread::native_handle_type, pthread_t>(),
              "Mismatched native handle type!");
#elif 0
static_assert(std::is_same<std::thread::native_handle_type, HANDLE>(),
              "Mismatched native handle type!");
#endif
// Interrupt a thread IF read_done is true, ensuring that lock is held
// when reading its value.
static void interrupt_thread(std::mutex &lock, const bool &read_done,
                             std::thread &thread) {
  std::unique_lock<std::mutex> locker(lock);
  if (!read_done) {
#ifndef _WIN32
    static_assert(std::is_same<std::thread::native_handle_type, pthread_t>::value,
                  "Bad native handle type");
    pthread_kill(thread.native_handle(), SIGPIPE);
#elif _MSC_VER
    static_assert(std::is_same<std::thread::native_handle_type, HANDLE>::value,
                  "Bad native handle type");
    CancelSynchronousIo(thread.native_handle());
#else
    (void)thread;
#endif
  }
}
BOOST_AUTO_TEST_CASE(can_create_connection) {
#ifndef _WIN32
  struct sigaction sigact;
  memset(&sigact, 0, sizeof sigact);
  sigact.sa_handler = donothing;
  sigemptyset(&sigact.sa_mask);
  sigaddset(&sigact.sa_mask, SIGPIPE);
  sigaction(SIGPIPE, &sigact, nullptr);
  BOOST_TEST(system("rm -rf -- \"$HOME/.sliprock\" /tmp/sliprock.*") == 0);
#endif
  SliprockConnection *con = nullptr;
  int x = sliprock_socket("dummy_val", sizeof("dummy_val") - 1, &con);
  BOOST_TEST(x == 0);
  BOOST_REQUIRE(x == 0);

  std::mutex lock, lock2;
  bool read_done = false, write_done = false;
  char buf[] = "Test message!\n";
  bool write_succeeded = false, read_succeeded = false;
  std::thread thread([&]() {
    if (!(read_succeeded = server(buf, con, read_done, lock2)))
      perror("sliprock_server");
  });
  std::thread thread2(
      [&]() { write_succeeded = client(buf, con, write_done, lock); });
  auto interrupter = std::thread{[&]() {
#ifndef _WIN32
    struct timespec q = {1, 0};
    nanosleep(&q, nullptr);
#else
    sliprock_trace("Calling Sleep()\n");
    Sleep(10000000);
#endif
    sliprock_trace("Interrupting thread\n");
    interrupt_thread(lock2, read_done, thread);
    interrupt_thread(lock, write_done, thread2);
  }};
  thread.join();
  thread2.join();
#ifdef _WIN32
  interrupter.detach();
#else
  interrupter.join();
#endif
  BOOST_TEST(write_succeeded);
  BOOST_TEST(read_succeeded);

  sliprock_close(con);
}
// BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include <iostream>
#include <lambda.hpp>
#include <cassert>

using namespace std;
using namespace Lambda;

template<typename _ID, typename _Expression>
void test(_ID const id, _Expression &&rre) {
	assert(rre);
	cout << "test " << id << " ok" << endl;
}

int main() {
	cout << boolalpha;

	{
		test("0001", !IsFunctor<int>::s_Value);
		test("0002", IsFunctor<Functor>::s_Value);
		test("0003", IsFunctor<Constant<int>>::s_Value);
		test("0004", IsFunctor<Bind<0>>::s_Value);
	}

	{
		int x = 0;
		test("0101", Bind<0>()(0) == 0);
		test("0102", Bind<0>()(1) == 1);
		test("0103", Bind<0>()(x) == 0);
		test("0104", Bind<0>()(x + 1) == 1);
		test("0105", Bind<0>()(0, 1) == 0);
		test("0106", Bind<0>()(x, x + 1) == 0);
		//test("", Bind<0>()(x + 1, x, x, x, x) == 1);
		//test("", Bind<0>()(1, 2, 3, 4, 5) == 1);
		//test("", Bind<2>()(x + 1, x, x, x, x) == 0);
		//test("", Bind<2>()(1, 2, 3, 4, 5) == 3);
	}

	{
		struct {} x;
		cout << &x << " " << (5 + 5) << endl;
	}

	{
		cout << (!_1)(false) << " " << (!_1)(true) << " " << (!!_1)(true) << endl;
		(cout << (_1 + 3))(5) << endl;
	}

	return 0;
}
<commit_msg>Moar testing<commit_after>#include <iostream>
#include <lambda.hpp>
#include <cassert>

using namespace std;
using namespace Lambda;

template<typename _ID, typename _Expression>
void test(_ID const id, _Expression &&rre) {
	assert(rre);
	cout << "test " << id << " ok" << endl;
}

int main() {
	cout << boolalpha;

	{
		test("0001", !IsFunctor<int>::s_Value);
		test("0002", IsFunctor<Functor>::s_Value);
		test("0003", IsFunctor<Constant<int>>::s_Value);
		test("0004", IsFunctor<Bind<0>>::s_Value);
	}

	{
		int x = 0;
		test("0101", Bind<0>()(0) == 0);
		test("0102", Bind<0>()(1) == 1);
		test("0103", Bind<0>()(x) == 0);
		test("0104", Bind<0>()(x + 1) == 1);
		test("0105", Bind<0>()(0, 1) == 0);
		test("0106", Bind<0>()(x, x + 1) == 0);
		test("0107", Bind<0>()(x + 1, x + 2) == 1);
		test("0108", Bind<1>()(0, 1) == 1);
		test("0109", Bind<1>()(0, 2) == 2);
		test("0110", Bind<1>()(2, 1) == 1);
		test("0111", Bind<1>()(x, 1) == 1);
		test("0112", Bind<1>()(1, x) == 0);
		test("0113", Bind<1>()(x, x + 1) == 1);
		test("0114", Bind<1>()(x + 1, x + 2) == 2);
		// TODO
	}

	{
		struct {} x;
		cout << &x << " " << (5 + 5) << endl;
	}

	{
		cout << (!_1)(false) << " " << (!_1)(true) << " " << (!!_1)(true) << endl;
		(cout << (_1 + 3))(5) << endl;
	}

	return 0;
}
<|endoftext|>