<commit_before>//  Copyright 2010 Gregory Szorc
//
//  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.

// this file contains cross-platform APIs
// if this gets too large, we should consider using a framework, like APR

#ifndef ZIPPYLOG_PLATFORM_HPP_
#define ZIPPYLOG_PLATFORM_HPP_

#include <zippylog/zippylog.h>

#include <string>
#include <vector>

using ::std::string;
using ::std::vector;

namespace zippylog {

// TODO move these to platform namespace
struct dir_entry {
    string name;
    uint64 size;
    char type;
};

// TODO define a type for function pointer so compiler can save us
ZIPPYLOG_EXPORT void * create_thread(void * func, void *data);

ZIPPYLOG_EXPORT bool join_thread(void *thread);

ZIPPYLOG_EXPORT bool terminate_thread(void *thread);

ZIPPYLOG_EXPORT bool directory_entries(const string dir, vector<dir_entry> &v);

ZIPPYLOG_EXPORT void windows_error(char *buffer, size_t buffer_size);

namespace platform {
    enum FileType {
        REGULAR = 1,
        DIRECTORY = 2,
        PIPE = 3,
        CHARACTER = 4,
        UNKNOWN = 5,
    };

    typedef struct FileStat {
        FileType type;
        int64 size;
    } FileStat;

    ZIPPYLOG_EXPORT bool stat(const string path, FileStat &st);

    typedef struct Time {
        int32 year;
        int32 mon;
        int32 mday;
        int32 hour;
        int32 min;
        int32 sec;
        int32 usec;
        int32 wday;
        int32 yday;
        int32 isdst;
        int64 epoch_micro;
        int32 epoch_sec;
    } Time;

    ZIPPYLOG_EXPORT bool TimeNow(Time &t);

    // converts number of microseconds since UNIX epoch into a zippylog Time struct
    ZIPPYLOG_EXPORT bool UnixMicroTimeToZippyTime(int64 from, Time &to);

    ZIPPYLOG_EXPORT bool MakeDirectory(const string path);

    ZIPPYLOG_EXPORT bool PathIsDirectory(const string path);

    typedef struct UUID {
        unsigned char data[16];
    } UUID;

    // creates a new UUID
    // UUID type is not defined yet
    bool CreateUUID(UUID &u);

    typedef struct File {
#ifdef WINDOWS
        void * handle;
#endif
        int fd;
    } File;

    enum FileFlags {
        READ = 1,
        WRITE = 2,
        APPEND = 3,
        CREATE = 4,
        TRUNCATE = 5,
        BINARY = 6,
    };

    bool OpenFile(File &f, const string path, int flags);

    // in the ideal world, timers would be represented as file descriptors and
    // we could include them in the zmq poll() event loop. this is easily done
    // on Linux. unfortunately, Windows requires a little bit more effort.
    // TODO expose timers as file descriptors someday
    class ZIPPYLOG_EXPORT Timer {
    public:
        // create a null timer. this does nothing and is present so some structs have
        // a default constructor
        Timer();

        // create a new timer that fires N microseconds from now
        Timer(uint32 microseconds);

        // whether the timer has signaled yet
        bool Signaled();

        // reset the timer
        // this will unarm the timer and prepare it to be executed again
        // this is called automatically by Start() if restarting an existing timer
        // it is more of an internal API but exposed in case it is needed
        bool Reset();

        // starts the timer
        bool Start();

    protected:
        uint32 microseconds;
        bool signaled;
        bool running;

#ifdef WINDOWS
        void * handle;
#endif
    };
}

} // namespace

#endif<commit_msg>note history of file<commit_after>//  Copyright 2010 Gregory Szorc
//
//  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.

// this file contains cross-platform APIs
// in the ideal world, we would use an existing library, like APR. In the early
// days of this project, it was decided to keep the code as free from external
// dependencies as possible. As this namespace becomes larger and larger, we
// have to start questioning that decision.

#ifndef ZIPPYLOG_PLATFORM_HPP_
#define ZIPPYLOG_PLATFORM_HPP_

#include <zippylog/zippylog.h>

#include <string>
#include <vector>

using ::std::string;
using ::std::vector;

namespace zippylog {

// TODO move these to platform namespace
struct dir_entry {
    string name;
    uint64 size;
    char type;
};

// TODO define a type for function pointer so compiler can save us
ZIPPYLOG_EXPORT void * create_thread(void * func, void *data);

ZIPPYLOG_EXPORT bool join_thread(void *thread);

ZIPPYLOG_EXPORT bool terminate_thread(void *thread);

ZIPPYLOG_EXPORT bool directory_entries(const string dir, vector<dir_entry> &v);

ZIPPYLOG_EXPORT void windows_error(char *buffer, size_t buffer_size);

namespace platform {
    enum FileType {
        REGULAR = 1,
        DIRECTORY = 2,
        PIPE = 3,
        CHARACTER = 4,
        UNKNOWN = 5,
    };

    typedef struct FileStat {
        FileType type;
        int64 size;
    } FileStat;

    ZIPPYLOG_EXPORT bool stat(const string path, FileStat &st);

    typedef struct Time {
        int32 year;
        int32 mon;
        int32 mday;
        int32 hour;
        int32 min;
        int32 sec;
        int32 usec;
        int32 wday;
        int32 yday;
        int32 isdst;
        int64 epoch_micro;
        int32 epoch_sec;
    } Time;

    ZIPPYLOG_EXPORT bool TimeNow(Time &t);

    // converts number of microseconds since UNIX epoch into a zippylog Time struct
    ZIPPYLOG_EXPORT bool UnixMicroTimeToZippyTime(int64 from, Time &to);

    ZIPPYLOG_EXPORT bool MakeDirectory(const string path);

    ZIPPYLOG_EXPORT bool PathIsDirectory(const string path);

    typedef struct UUID {
        unsigned char data[16];
    } UUID;

    // creates a new UUID
    // UUID type is not defined yet
    bool CreateUUID(UUID &u);

    typedef struct File {
#ifdef WINDOWS
        void * handle;
#endif
        int fd;
    } File;

    enum FileFlags {
        READ = 1,
        WRITE = 2,
        APPEND = 3,
        CREATE = 4,
        TRUNCATE = 5,
        BINARY = 6,
    };

    bool OpenFile(File &f, const string path, int flags);

    // in the ideal world, timers would be represented as file descriptors and
    // we could include them in the zmq poll() event loop. this is easily done
    // on Linux. unfortunately, Windows requires a little bit more effort.
    // TODO expose timers as file descriptors someday
    class ZIPPYLOG_EXPORT Timer {
    public:
        // create a null timer. this does nothing and is present so some structs have
        // a default constructor
        Timer();

        // create a new timer that fires N microseconds from now
        Timer(uint32 microseconds);

        // whether the timer has signaled yet
        bool Signaled();

        // reset the timer
        // this will unarm the timer and prepare it to be executed again
        // this is called automatically by Start() if restarting an existing timer
        // it is more of an internal API but exposed in case it is needed
        bool Reset();

        // starts the timer
        bool Start();

    protected:
        uint32 microseconds;
        bool signaled;
        bool running;

#ifdef WINDOWS
        void * handle;
#endif
    };
}

} // namespace

#endif<|endoftext|>


<commit_before>//  Copyright 2010 Gregory Szorc
//
//  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 <zippylog/streamer.hpp>
#include <zippylog/protocol/request.pb.h>
#include <zippylog/protocol/response.pb.h>
#include <zippylog/zippylogd.pb.h>
#include <zippylog/zeromq.hpp>

using ::zippylog::protocol::response::SubscribeAck;
using ::zippylog::zippylogd::StreamerStartup;
using ::zippylog::zippylogd::StreamerShutdown;
using ::zippylog::zippylogd::StreamerSubscriptionExpired;
using ::zippylog::zippylogd::StreamerReceiveKeepalive;
using ::zippylog::zippylogd::StreamerRejectKeepaliveUnknownSubscription;
using ::zippylog::zippylogd::StreamerSubscriptionRenewedFromKeepalive;
using ::zippylog::zippylogd::StreamerErrorRenewingSubscription;
using ::zmq::message_t;

#define LOG_MESSAGE(msgvar, socketvar) { \
    msgvar.set_id(this->id); \
    Envelope logenvelope = Envelope(); \
    msgvar.add_to_envelope(&logenvelope); \
    zeromq::send_envelope(socketvar, logenvelope); \
}

namespace zippylog {
namespace server {

StoreChangeSubscription::StoreChangeSubscription()
{

}

SubscriptionInfo::SubscriptionInfo()
{
}

SubscriptionInfo::SubscriptionInfo(uint32 expiration_ttl)
{
    this->expiration_timer = Timer(expiration_ttl * 1000000);
    if (!this->expiration_timer.Start()) {
        throw "could not start expiration timer";
    }
}

Streamer::Streamer(Store *store,
                   context_t *zctx,
                   const string store_changes_endpoint,
                   const string client_endpoint,
                   const string subscriptions_endpoint,
                   const string subscription_updates_endpoint,
                   const string logging_endpoint,
                   uint32 subscription_ttl)
{
    this->store = store;
    this->zctx = zctx;
    this->store_changes_endpoint = store_changes_endpoint;
    this->client_endpoint = client_endpoint;
    this->subscriptions_endpoint = subscriptions_endpoint;
    this->subscription_updates_endpoint = subscription_updates_endpoint;
    this->logging_endpoint = logging_endpoint;
    this->subscription_ttl = subscription_ttl;

    this->changes_sock = NULL;
    this->client_sock = NULL;
    this->subscriptions_sock = NULL;
    this->subscription_updates_sock = NULL;
    this->logging_sock = NULL;

    platform::UUID uuid;
    if (!platform::CreateUUID(uuid)) {
        throw "could not create UUID";
    }

    this->id = string((const char *)&uuid, sizeof(uuid));
}

Streamer::~Streamer()
{
    if (this->changes_sock) delete this->changes_sock;
    if (this->client_sock) delete this->client_sock;
    if (this->subscriptions_sock) delete this->subscriptions_sock;
    if (this->subscription_updates_sock) delete this->subscription_updates_sock;
    if (this->logging_sock) delete this->logging_sock;
}

void Streamer::SetShutdownSemaphore(bool *active)
{
    if (!active) throw "pointer must not be NULL";

    if (!*active) throw "boolean being pointed to must be true";

    this->active = active;
}

void Streamer::Run()
{
    this->logging_sock = new socket_t(*this->zctx, ZMQ_PUSH);
    this->logging_sock->connect(this->logging_endpoint.c_str());

    {
        StreamerStartup log = StreamerStartup();
        LOG_MESSAGE(log, this->logging_sock);
    }

    // subscribe to store change notifications
    this->changes_sock = new socket_t(*this->zctx, ZMQ_SUB);
    this->changes_sock->setsockopt(ZMQ_SUBSCRIBE, NULL, 0);
    this->changes_sock->connect(this->store_changes_endpoint.c_str());

    // establish sending socket
    this->client_sock = new socket_t(*this->zctx, ZMQ_PUSH);
    this->client_sock->connect(this->client_endpoint.c_str());

    // receive client subscriptions
    this->subscriptions_sock = new socket_t(*this->zctx, ZMQ_PULL);
    this->subscriptions_sock->connect(this->subscriptions_endpoint.c_str());

    // receive client updates
    this->subscription_updates_sock = new socket_t(*this->zctx, ZMQ_SUB);
    this->subscription_updates_sock->connect(this->subscription_updates_endpoint.c_str());
    this->subscription_updates_sock->setsockopt(ZMQ_SUBSCRIBE, "", 0);

    zmq::pollitem_t pollitems[3];
    pollitems[0].events = ZMQ_POLLIN;
    pollitems[0].socket = *this->changes_sock;
    pollitems[0].fd = 0;
    pollitems[0].revents = 0;

    pollitems[1].events = ZMQ_POLLIN;
    pollitems[1].socket = *this->subscriptions_sock;
    pollitems[1].fd = 0;
    pollitems[1].revents = 0;

    pollitems[2].events = ZMQ_POLLIN;
    pollitems[2].socket = *this->subscription_updates_sock;
    pollitems[2].fd = 0;
    pollitems[2].revents = 0;

    while (*this->active) {
        zmq::message_t msg;

        // wait for a message to process
        int rc = zmq::poll(&pollitems[0], 3, 250000);

        // process subscription updates first
        if (pollitems[2].revents & ZMQ_POLLIN) {
            if (!this->subscription_updates_sock->recv(&msg, 0)) {
                throw "weird";
            }

            Envelope e = Envelope(&msg);
            assert(e.number_messages() == 1);
            assert(e.message_namespace(0) == 1);

            uint32 type = e.message_type(0);

            if (type == protocol::request::SubscribeKeepalive::zippylog_enumeration) {
                protocol::request::SubscribeKeepalive *m =
                    (protocol::request::SubscribeKeepalive *)e.get_message(0);

                string id = m->id();
                delete m;

                StreamerReceiveKeepalive log = StreamerReceiveKeepalive();
                log.set_subscription(id);
                LOG_MESSAGE(log, this->logging_sock);

                if (this->HasSubscription(id)) {
                    if (this->RenewSubscription(id)) {
                        StreamerSubscriptionRenewedFromKeepalive log = StreamerSubscriptionRenewedFromKeepalive();
                        log.set_subscription(id);
                        LOG_MESSAGE(log, this->logging_sock);
                    }
                    else {
                        StreamerErrorRenewingSubscription log = StreamerErrorRenewingSubscription();
                        log.set_subscription(id);
                        LOG_MESSAGE(log, this->logging_sock);
                    }
                }
                else {
                    StreamerRejectKeepaliveUnknownSubscription log = StreamerRejectKeepaliveUnknownSubscription();
                    log.set_subscription(id);
                    LOG_MESSAGE(log, this->logging_sock);
                }
            }
        }

        // unsubscribe any expired subscribers
        map<string, SubscriptionInfo>::iterator iter = this->subscriptions.begin();
        for (; iter != this->subscriptions.end(); iter++) {
            if (iter->second.expiration_timer.Signaled()) {
                StreamerSubscriptionExpired log = StreamerSubscriptionExpired();
                log.set_subscription(iter->first);
                LOG_MESSAGE(log, this->logging_sock);
                this->subscriptions.erase(iter);
                break;
            }
        }

        // process new subscriptions
        if (pollitems[1].revents & ZMQ_POLLIN) {
            vector<string> identities;
            vector<message_t *> msgs;

            if (!zeromq::receive_multipart_message(this->subscriptions_sock, identities, msgs)) {
                // TODO log error here
                continue;
            }

            assert(msgs.size() > 0);

            Envelope e = Envelope(msgs[0]);
            assert(e.number_messages() == 1);
            assert(e.message_namespace(0) == 1);
            assert(e.message_type(0) == protocol::request::SubscribeStoreChanges::zippylog_enumeration);

            protocol::request::SubscribeStoreChanges *m = (protocol::request::SubscribeStoreChanges *)e.get_message(0);

            StoreChangeSubscription subscription;

            for (int i = 0; i < m->path_size(); i++) {
                subscription.paths.push_back(m->path(i));
            }

            delete m;

            subscription.socket_identifiers = identities;

            // TODO create subscription identity properly
            platform::UUID uuid;
            if (!platform::CreateUUID(uuid)) {
                throw "could not create UUID";
            }
            subscription.id = string((const char *)&uuid, sizeof(uuid));

            this->store_change_subscriptions.push_back(subscription);

            SubscriptionInfo info = SubscriptionInfo(this->subscription_ttl);

            this->subscriptions[subscription.id] = info;

            // send ACK response to client
            SubscribeAck ack = SubscribeAck();
            ack.set_id(subscription.id);
            ack.set_ttl(this->subscription_ttl / 1000);
            Envelope response = Envelope();

            // copy tags to response because that's what the protocol does
            for (size_t i = 0; i < e.envelope.tag_size(); i++) {
                response.envelope.add_tag(e.envelope.tag(i));
            }

            ack.add_to_envelope(&response);

            if (!zeromq::send_envelope(this->client_sock, identities, response)) {
                // TODO log error here
                assert(0);
            }

            for (vector<message_t *>::iterator msg = msgs.begin(); msg != msgs.end(); msg++) {
                delete *msg;
            }
            msgs.clear();

        }

        // process store changes and send to subscribers
        if (pollitems[0].revents & ZMQ_POLLIN) {
            this->changes_sock->recv(&msg, 0);

            // if we don't have any subscriptions, do nothing
            if (!this->store_change_subscriptions.size()) {
                continue;
            }

            Envelope e = Envelope(&msg);

            assert(e.number_messages());
            // TODO magic constant
            assert(e.message_namespace(0) == 1);

            uint32 message_type = e.message_type(0);
            switch (message_type) {
                case protocol::StoreChangeBucketAdded::zippylog_enumeration:
                case protocol::StoreChangeBucketDeleted::zippylog_enumeration:
                case protocol::StoreChangeStreamSetAdded::zippylog_enumeration:
                case protocol::StoreChangeStreamSetDeleted::zippylog_enumeration:
                case protocol::StoreChangeStreamAppended::zippylog_enumeration:
                case protocol::StoreChangeStreamAdded::zippylog_enumeration:
                case protocol::StoreChangeStreamDeleted::zippylog_enumeration:
                    // if no subscriptions to store changes, do nothing
                    if (!this->store_change_subscriptions.size()) break;

                    this->ProcessStoreChangeEnvelope(e);
                    break;
                default:
                    // WTF mate?
                    break;
            }
        }
    }

    StreamerShutdown log = StreamerShutdown();
    LOG_MESSAGE(log, this->logging_sock);
}

void Streamer::ProcessStoreChangeEnvelope(Envelope &e)
{
    // we obtain the full path and build a path from it
    // we then compare path prefixes of subscribers to see who gets it
    string bucket, stream_set, stream;

    switch (e.message_type(0)) {
        case protocol::StoreChangeBucketAdded::zippylog_enumeration:
        {
            protocol::StoreChangeBucketAdded *m = (protocol::StoreChangeBucketAdded *)e.get_message(0);
            bucket = m->bucket();
            delete m;
        }
            break;

        case protocol::StoreChangeBucketDeleted::zippylog_enumeration:
        {
            protocol::StoreChangeBucketDeleted *m = (protocol::StoreChangeBucketDeleted *)e.get_message(0);
            bucket = m->bucket();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamSetAdded::zippylog_enumeration:
        {
            protocol::StoreChangeStreamSetAdded *m = (protocol::StoreChangeStreamSetAdded *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamSetDeleted::zippylog_enumeration:
        {
            protocol::StoreChangeStreamSetDeleted *m = (protocol::StoreChangeStreamSetDeleted *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamAppended::zippylog_enumeration:
        {
            protocol::StoreChangeStreamAppended *m = (protocol::StoreChangeStreamAppended *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            stream = m->stream();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamAdded::zippylog_enumeration:
        {
            protocol::StoreChangeStreamAdded *m = (protocol::StoreChangeStreamAdded *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            stream = m->stream();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamDeleted::zippylog_enumeration:
        {
            protocol::StoreChangeStreamDeleted *m = (protocol::StoreChangeStreamDeleted *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            stream = m->stream();
            delete m;
        }
            break;
    }

    string path;
    if (!stream.empty()) {
        path = Store::StreamPath(bucket, stream_set, stream);
    }
    else if (!stream_set.empty()) {
        path = Store::StreamsetPath(bucket, stream_set);
    }
    else {
        path = Store::BucketPath(bucket);
    }

    // iterate over subscribers
    vector<StoreChangeSubscription>::iterator i;
    for (i = this->store_change_subscriptions.begin(); i != this->store_change_subscriptions.end(); i++) {

        // iterate over paths they are subscribed to
        vector<string>::iterator prefix;
        for (prefix = i->paths.begin(); prefix != i->paths.end(); i++) {
            // no way that will match
            if (prefix->length() > path.length()) continue;

            // if the subscribed prefix doesn't match the changed prefix
            if (path.substr(0, prefix->length()).compare(*prefix)) continue;

            // at this point, they must be subscribed, so we send them the event

            Envelope response = Envelope();
            protocol::response::SubscriptionStart start = protocol::response::SubscriptionStart();
            start.set_id(i->id);
            start.add_to_envelope(&response);

            if (!e.CopyMessage(0, response)) {
                throw "could not copy message to response envelope. weird";
            }

            zeromq::send_envelope(this->client_sock, i->socket_identifiers, response);

            // don't process this path any more for this subscriber
            break;
        }
    }
}

bool Streamer::HasSubscription(const string &id)
{
    map<string, SubscriptionInfo>::iterator iter = this->subscriptions.find(id);

    return iter != this->subscriptions.end();
}

bool Streamer::RenewSubscription(const string &id)
{
    map<string, SubscriptionInfo>::iterator iter = this->subscriptions.find(id);

    if (iter == this->subscriptions.end()) {
        return false;
    }

    return iter->second.expiration_timer.Start();
}

}} // namespaces
<commit_msg>proper unit conversion<commit_after>//  Copyright 2010 Gregory Szorc
//
//  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 <zippylog/streamer.hpp>
#include <zippylog/protocol/request.pb.h>
#include <zippylog/protocol/response.pb.h>
#include <zippylog/zippylogd.pb.h>
#include <zippylog/zeromq.hpp>

using ::zippylog::protocol::response::SubscribeAck;
using ::zippylog::zippylogd::StreamerStartup;
using ::zippylog::zippylogd::StreamerShutdown;
using ::zippylog::zippylogd::StreamerSubscriptionExpired;
using ::zippylog::zippylogd::StreamerReceiveKeepalive;
using ::zippylog::zippylogd::StreamerRejectKeepaliveUnknownSubscription;
using ::zippylog::zippylogd::StreamerSubscriptionRenewedFromKeepalive;
using ::zippylog::zippylogd::StreamerErrorRenewingSubscription;
using ::zmq::message_t;

#define LOG_MESSAGE(msgvar, socketvar) { \
    msgvar.set_id(this->id); \
    Envelope logenvelope = Envelope(); \
    msgvar.add_to_envelope(&logenvelope); \
    zeromq::send_envelope(socketvar, logenvelope); \
}

namespace zippylog {
namespace server {

StoreChangeSubscription::StoreChangeSubscription()
{

}

SubscriptionInfo::SubscriptionInfo()
{
}

SubscriptionInfo::SubscriptionInfo(uint32 expiration_ttl)
{
    // milliseconds to microseconds
    this->expiration_timer = Timer(expiration_ttl * 1000);
    if (!this->expiration_timer.Start()) {
        throw "could not start expiration timer";
    }
}

Streamer::Streamer(Store *store,
                   context_t *zctx,
                   const string store_changes_endpoint,
                   const string client_endpoint,
                   const string subscriptions_endpoint,
                   const string subscription_updates_endpoint,
                   const string logging_endpoint,
                   uint32 subscription_ttl)
{
    this->store = store;
    this->zctx = zctx;
    this->store_changes_endpoint = store_changes_endpoint;
    this->client_endpoint = client_endpoint;
    this->subscriptions_endpoint = subscriptions_endpoint;
    this->subscription_updates_endpoint = subscription_updates_endpoint;
    this->logging_endpoint = logging_endpoint;
    this->subscription_ttl = subscription_ttl;

    this->changes_sock = NULL;
    this->client_sock = NULL;
    this->subscriptions_sock = NULL;
    this->subscription_updates_sock = NULL;
    this->logging_sock = NULL;

    platform::UUID uuid;
    if (!platform::CreateUUID(uuid)) {
        throw "could not create UUID";
    }

    this->id = string((const char *)&uuid, sizeof(uuid));
}

Streamer::~Streamer()
{
    if (this->changes_sock) delete this->changes_sock;
    if (this->client_sock) delete this->client_sock;
    if (this->subscriptions_sock) delete this->subscriptions_sock;
    if (this->subscription_updates_sock) delete this->subscription_updates_sock;
    if (this->logging_sock) delete this->logging_sock;
}

void Streamer::SetShutdownSemaphore(bool *active)
{
    if (!active) throw "pointer must not be NULL";

    if (!*active) throw "boolean being pointed to must be true";

    this->active = active;
}

void Streamer::Run()
{
    this->logging_sock = new socket_t(*this->zctx, ZMQ_PUSH);
    this->logging_sock->connect(this->logging_endpoint.c_str());

    {
        StreamerStartup log = StreamerStartup();
        LOG_MESSAGE(log, this->logging_sock);
    }

    // subscribe to store change notifications
    this->changes_sock = new socket_t(*this->zctx, ZMQ_SUB);
    this->changes_sock->setsockopt(ZMQ_SUBSCRIBE, NULL, 0);
    this->changes_sock->connect(this->store_changes_endpoint.c_str());

    // establish sending socket
    this->client_sock = new socket_t(*this->zctx, ZMQ_PUSH);
    this->client_sock->connect(this->client_endpoint.c_str());

    // receive client subscriptions
    this->subscriptions_sock = new socket_t(*this->zctx, ZMQ_PULL);
    this->subscriptions_sock->connect(this->subscriptions_endpoint.c_str());

    // receive client updates
    this->subscription_updates_sock = new socket_t(*this->zctx, ZMQ_SUB);
    this->subscription_updates_sock->connect(this->subscription_updates_endpoint.c_str());
    this->subscription_updates_sock->setsockopt(ZMQ_SUBSCRIBE, "", 0);

    zmq::pollitem_t pollitems[3];
    pollitems[0].events = ZMQ_POLLIN;
    pollitems[0].socket = *this->changes_sock;
    pollitems[0].fd = 0;
    pollitems[0].revents = 0;

    pollitems[1].events = ZMQ_POLLIN;
    pollitems[1].socket = *this->subscriptions_sock;
    pollitems[1].fd = 0;
    pollitems[1].revents = 0;

    pollitems[2].events = ZMQ_POLLIN;
    pollitems[2].socket = *this->subscription_updates_sock;
    pollitems[2].fd = 0;
    pollitems[2].revents = 0;

    while (*this->active) {
        zmq::message_t msg;

        // wait for a message to process
        int rc = zmq::poll(&pollitems[0], 3, 250000);

        // process subscription updates first
        if (pollitems[2].revents & ZMQ_POLLIN) {
            if (!this->subscription_updates_sock->recv(&msg, 0)) {
                throw "weird";
            }

            Envelope e = Envelope(&msg);
            assert(e.number_messages() == 1);
            assert(e.message_namespace(0) == 1);

            uint32 type = e.message_type(0);

            if (type == protocol::request::SubscribeKeepalive::zippylog_enumeration) {
                protocol::request::SubscribeKeepalive *m =
                    (protocol::request::SubscribeKeepalive *)e.get_message(0);

                string id = m->id();
                delete m;

                StreamerReceiveKeepalive log = StreamerReceiveKeepalive();
                log.set_subscription(id);
                LOG_MESSAGE(log, this->logging_sock);

                if (this->HasSubscription(id)) {
                    if (this->RenewSubscription(id)) {
                        StreamerSubscriptionRenewedFromKeepalive log = StreamerSubscriptionRenewedFromKeepalive();
                        log.set_subscription(id);
                        LOG_MESSAGE(log, this->logging_sock);
                    }
                    else {
                        StreamerErrorRenewingSubscription log = StreamerErrorRenewingSubscription();
                        log.set_subscription(id);
                        LOG_MESSAGE(log, this->logging_sock);
                    }
                }
                else {
                    StreamerRejectKeepaliveUnknownSubscription log = StreamerRejectKeepaliveUnknownSubscription();
                    log.set_subscription(id);
                    LOG_MESSAGE(log, this->logging_sock);
                }
            }
        }

        // unsubscribe any expired subscribers
        map<string, SubscriptionInfo>::iterator iter = this->subscriptions.begin();
        for (; iter != this->subscriptions.end(); iter++) {
            if (iter->second.expiration_timer.Signaled()) {
                StreamerSubscriptionExpired log = StreamerSubscriptionExpired();
                log.set_subscription(iter->first);
                LOG_MESSAGE(log, this->logging_sock);
                this->subscriptions.erase(iter);
                break;
            }
        }

        // process new subscriptions
        if (pollitems[1].revents & ZMQ_POLLIN) {
            vector<string> identities;
            vector<message_t *> msgs;

            if (!zeromq::receive_multipart_message(this->subscriptions_sock, identities, msgs)) {
                // TODO log error here
                continue;
            }

            assert(msgs.size() > 0);

            Envelope e = Envelope(msgs[0]);
            assert(e.number_messages() == 1);
            assert(e.message_namespace(0) == 1);
            assert(e.message_type(0) == protocol::request::SubscribeStoreChanges::zippylog_enumeration);

            protocol::request::SubscribeStoreChanges *m = (protocol::request::SubscribeStoreChanges *)e.get_message(0);

            StoreChangeSubscription subscription;

            for (int i = 0; i < m->path_size(); i++) {
                subscription.paths.push_back(m->path(i));
            }

            delete m;

            subscription.socket_identifiers = identities;

            // TODO create subscription identity properly
            platform::UUID uuid;
            if (!platform::CreateUUID(uuid)) {
                throw "could not create UUID";
            }
            subscription.id = string((const char *)&uuid, sizeof(uuid));

            this->store_change_subscriptions.push_back(subscription);

            SubscriptionInfo info = SubscriptionInfo(this->subscription_ttl);

            this->subscriptions[subscription.id] = info;

            // send ACK response to client
            SubscribeAck ack = SubscribeAck();
            ack.set_id(subscription.id);
            ack.set_ttl(this->subscription_ttl / 1000);
            Envelope response = Envelope();

            // copy tags to response because that's what the protocol does
            for (size_t i = 0; i < e.envelope.tag_size(); i++) {
                response.envelope.add_tag(e.envelope.tag(i));
            }

            ack.add_to_envelope(&response);

            if (!zeromq::send_envelope(this->client_sock, identities, response)) {
                // TODO log error here
                assert(0);
            }

            for (vector<message_t *>::iterator msg = msgs.begin(); msg != msgs.end(); msg++) {
                delete *msg;
            }
            msgs.clear();

        }

        // process store changes and send to subscribers
        if (pollitems[0].revents & ZMQ_POLLIN) {
            this->changes_sock->recv(&msg, 0);

            // if we don't have any subscriptions, do nothing
            if (!this->store_change_subscriptions.size()) {
                continue;
            }

            Envelope e = Envelope(&msg);

            assert(e.number_messages());
            // TODO magic constant
            assert(e.message_namespace(0) == 1);

            uint32 message_type = e.message_type(0);
            switch (message_type) {
                case protocol::StoreChangeBucketAdded::zippylog_enumeration:
                case protocol::StoreChangeBucketDeleted::zippylog_enumeration:
                case protocol::StoreChangeStreamSetAdded::zippylog_enumeration:
                case protocol::StoreChangeStreamSetDeleted::zippylog_enumeration:
                case protocol::StoreChangeStreamAppended::zippylog_enumeration:
                case protocol::StoreChangeStreamAdded::zippylog_enumeration:
                case protocol::StoreChangeStreamDeleted::zippylog_enumeration:
                    // if no subscriptions to store changes, do nothing
                    if (!this->store_change_subscriptions.size()) break;

                    this->ProcessStoreChangeEnvelope(e);
                    break;
                default:
                    // WTF mate?
                    break;
            }
        }
    }

    StreamerShutdown log = StreamerShutdown();
    LOG_MESSAGE(log, this->logging_sock);
}

void Streamer::ProcessStoreChangeEnvelope(Envelope &e)
{
    // we obtain the full path and build a path from it
    // we then compare path prefixes of subscribers to see who gets it
    string bucket, stream_set, stream;

    switch (e.message_type(0)) {
        case protocol::StoreChangeBucketAdded::zippylog_enumeration:
        {
            protocol::StoreChangeBucketAdded *m = (protocol::StoreChangeBucketAdded *)e.get_message(0);
            bucket = m->bucket();
            delete m;
        }
            break;

        case protocol::StoreChangeBucketDeleted::zippylog_enumeration:
        {
            protocol::StoreChangeBucketDeleted *m = (protocol::StoreChangeBucketDeleted *)e.get_message(0);
            bucket = m->bucket();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamSetAdded::zippylog_enumeration:
        {
            protocol::StoreChangeStreamSetAdded *m = (protocol::StoreChangeStreamSetAdded *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamSetDeleted::zippylog_enumeration:
        {
            protocol::StoreChangeStreamSetDeleted *m = (protocol::StoreChangeStreamSetDeleted *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamAppended::zippylog_enumeration:
        {
            protocol::StoreChangeStreamAppended *m = (protocol::StoreChangeStreamAppended *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            stream = m->stream();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamAdded::zippylog_enumeration:
        {
            protocol::StoreChangeStreamAdded *m = (protocol::StoreChangeStreamAdded *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            stream = m->stream();
            delete m;
        }
            break;

        case protocol::StoreChangeStreamDeleted::zippylog_enumeration:
        {
            protocol::StoreChangeStreamDeleted *m = (protocol::StoreChangeStreamDeleted *)e.get_message(0);
            bucket = m->bucket();
            stream_set = m->stream_set();
            stream = m->stream();
            delete m;
        }
            break;
    }

    string path;
    if (!stream.empty()) {
        path = Store::StreamPath(bucket, stream_set, stream);
    }
    else if (!stream_set.empty()) {
        path = Store::StreamsetPath(bucket, stream_set);
    }
    else {
        path = Store::BucketPath(bucket);
    }

    // iterate over subscribers
    vector<StoreChangeSubscription>::iterator i;
    for (i = this->store_change_subscriptions.begin(); i != this->store_change_subscriptions.end(); i++) {

        // iterate over paths they are subscribed to
        vector<string>::iterator prefix;
        for (prefix = i->paths.begin(); prefix != i->paths.end(); i++) {
            // no way that will match
            if (prefix->length() > path.length()) continue;

            // if the subscribed prefix doesn't match the changed prefix
            if (path.substr(0, prefix->length()).compare(*prefix)) continue;

            // at this point, they must be subscribed, so we send them the event

            Envelope response = Envelope();
            protocol::response::SubscriptionStart start = protocol::response::SubscriptionStart();
            start.set_id(i->id);
            start.add_to_envelope(&response);

            if (!e.CopyMessage(0, response)) {
                throw "could not copy message to response envelope. weird";
            }

            zeromq::send_envelope(this->client_sock, i->socket_identifiers, response);

            // don't process this path any more for this subscriber
            break;
        }
    }
}

bool Streamer::HasSubscription(const string &id)
{
    map<string, SubscriptionInfo>::iterator iter = this->subscriptions.find(id);

    return iter != this->subscriptions.end();
}

bool Streamer::RenewSubscription(const string &id)
{
    map<string, SubscriptionInfo>::iterator iter = this->subscriptions.find(id);

    if (iter == this->subscriptions.end()) {
        return false;
    }

    return iter->second.expiration_timer.Start();
}

}} // namespaces
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: componentfactory.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 02:54:42 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _COMPHELPER_COMPONENTFACTORY_HXX
#include <comphelper/componentfactory.hxx>
#endif
#ifndef _COMPHELPER_PROCESSFACTORY_HXX_
#include <comphelper/processfactory.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HDL_
#include <com/sun/star/registry/XRegistryKey.hpp>
#endif

#ifndef _CPPUHELPER_SHLIB_HXX_
#include <cppuhelper/shlib.hxx>
#endif

#ifndef GCC
#pragma hdrstop
#endif

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::registry;
using namespace ::rtl;

namespace comphelper
{

Reference< XInterface > getComponentInstance(
            const OUString & rLibraryName,
            const OUString & rImplementationName
            )
{
    Reference< XInterface > xI;
    Reference< XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
    if ( xMSF.is() )
        xI = xMSF->createInstance( rImplementationName );
    if( !xI.is() )
    {
        Reference< XSingleServiceFactory > xSSF =
            loadLibComponentFactory( rLibraryName, rImplementationName,
            Reference< XMultiServiceFactory >(), Reference< XRegistryKey >() );
        if (xSSF.is())
            xI = xSSF->createInstance();
    }
    return xI;
}

Reference< XSingleServiceFactory > loadLibComponentFactory(
            const OUString & rLibName,
            const OUString & rImplName,
            const Reference< XMultiServiceFactory > & xSF,
            const Reference< XRegistryKey > & xKey
            )
{
    return Reference< XSingleServiceFactory >( ::cppu::loadSharedLibComponentFactory(
        rLibName, OUString(), rImplName, xSF, xKey ), UNO_QUERY );
}

}   // namespace comphelper
<commit_msg>INTEGRATION: CWS pchfix02 (1.5.100); FILE MERGED 2006/09/01 17:19:45 kaib 1.5.100.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: componentfactory.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 17:15:55 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_comphelper.hxx"

#ifndef _COMPHELPER_COMPONENTFACTORY_HXX
#include <comphelper/componentfactory.hxx>
#endif
#ifndef _COMPHELPER_PROCESSFACTORY_HXX_
#include <comphelper/processfactory.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HDL_
#include <com/sun/star/registry/XRegistryKey.hpp>
#endif

#ifndef _CPPUHELPER_SHLIB_HXX_
#include <cppuhelper/shlib.hxx>
#endif

#ifndef GCC
#endif

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::registry;
using namespace ::rtl;

namespace comphelper
{

Reference< XInterface > getComponentInstance(
            const OUString & rLibraryName,
            const OUString & rImplementationName
            )
{
    Reference< XInterface > xI;
    Reference< XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
    if ( xMSF.is() )
        xI = xMSF->createInstance( rImplementationName );
    if( !xI.is() )
    {
        Reference< XSingleServiceFactory > xSSF =
            loadLibComponentFactory( rLibraryName, rImplementationName,
            Reference< XMultiServiceFactory >(), Reference< XRegistryKey >() );
        if (xSSF.is())
            xI = xSSF->createInstance();
    }
    return xI;
}

Reference< XSingleServiceFactory > loadLibComponentFactory(
            const OUString & rLibName,
            const OUString & rImplName,
            const Reference< XMultiServiceFactory > & xSF,
            const Reference< XRegistryKey > & xKey
            )
{
    return Reference< XSingleServiceFactory >( ::cppu::loadSharedLibComponentFactory(
        rLibName, OUString(), rImplName, xSF, xKey ), UNO_QUERY );
}

}   // namespace comphelper
<|endoftext|>


<commit_before><commit_msg>Fixed a potential buffer overrun when falling back from sendfile to normal read/write<commit_after><|endoftext|>


<commit_before>#include <sstream>
#include "slice.hpp"

namespace Vole {

  using std::stringstream;

  template <typename T>
  template <typename Allocator>
  Slice<T>::Slice(Allocator& a, size_t l, size_t c)
  : mem(a.template alloc<T>(c)),
    beg(mem),
    len(l),
    cap(c)
  { }

  template <typename T>
  T& Slice<T>::operator[](size_t i) {
    if (!(i < len)) {
      // TODO: use an error class with more metadata
      throw "slice index out of bounds";
    }
    return beg[i];
  }

  template <typename T>
  Slice<T> Slice<T>::slice(size_t lower, size_t upper) {
    if (upper > len || lower > upper) {
      // TODO: use an error class with more metadata
      throw "invalid range for slice";
    }
    return { mem, beg + lower, upper - lower, cap - lower };
  }

  template <typename T>
  T& Slice<T>::first() {
    return (*this)[0];
  }

  template <typename T>
  T& Slice<T>::last() {
    return (*this)[len-1];
  }

  template <typename T>
  Slice<T> Slice<T>::take(size_t n) {
    return slice(0, n);
  }

  template <typename T>
  Slice<T> Slice<T>::drop(size_t n) {
    return slice(n, len);
  }

  template <typename T>
  Slice<T>::operator string() {
    stringstream ss;
    ss << '(';
    for (size_t i = 0; i < len; ++i) {
      ss << (i ? " " : "") << beg[i];
    }
    ss << ')';
    return ss.str();
  }
}<commit_msg>constructor error<commit_after>#include <iostream>
#include <sstream>
#include "slice.hpp"

namespace Vole {

  using std::stringstream;

  template <typename T>
  template <typename Allocator>
  Slice<T>::Slice(Allocator& a, size_t l, size_t c)
  : mem(a.template alloc<T>(c)),
    beg(mem),
    len(l),
    cap(c)
  { }

  template <typename T>
  T& Slice<T>::operator[](size_t i) {
    if (!(i < len)) {
      // TODO: use an error class with more metadata
      throw "slice index out of bounds";
    }
    return beg[i];
  }

  template <typename T>
  Slice<T> Slice<T>::slice(size_t lower, size_t upper) {
    if (upper > len || lower > upper) {
      // TODO: use an error class with more metadata
      throw "invalid range for slice";
    }
    return { mem, beg + lower, upper - lower, cap - lower };
  }

  template <typename T>
  T& Slice<T>::first() {
    return (*this)[0];
  }

  template <typename T>
  T& Slice<T>::last() {
    return (*this)[len-1];
  }

  template <typename T>
  Slice<T> Slice<T>::take(size_t n) {
    return slice(0, n);
  }

  template <typename T>
  Slice<T> Slice<T>::drop(size_t n) {
    return slice(n, len);
  }

  template <typename T>
  Slice<T>::operator string() {
    stringstream ss;
    ss << '(';
    for (size_t i = 0; i < len; ++i) {
      ss << (i ? " " : "") << beg[i];
    }
    ss << ')';
    return ss.str();
  }

  template <typename T, typename Allocator>
  Slice<T> append(Allocator& alloc, Slice<T> s, T t) {
    if (s.len < s.cap) {
      s[s.len] = t;
      Slice<T> newslice ( s.mem, s.beg, s.len+1, s.cap );
      return newslice;
    } else {
      auto newslice { alloc, s.len+1, s.cap*2 };
      for (int i = 0; i < s.len; i++) {
        newslice[i] = s[i];
      }
      newslice[s.len] = t;
      return newslice;
    }
  }

  template <typename T, typename Allocator>
  Slice<T> append(Allocator& alloc, Slice<T> s1, Slice<T> s2) {
    if (s1.len+s2.len < s1.cap) {
      for (int i = 0; i < s2.len; i++) {
        s1[s1.len+i] = s2[i];
      }
      return { s1.mem, s1.beg, s1.len+s2.len, s1.cap };
    } else {
      auto newslice { alloc, s1.len+s2.len, (s1.cap+s2.len)*2 };
      for (int i = 0; i < s1.len; i++) {
        newslice[i] = s1[i];
      }
      for (int i = 0; i < s2.len; i++) {
        newslice[s1.len+i] = s2[i];
      }
      return newslice;
    }
  }

}

using namespace std;
using namespace Vole;

class New {
public:
  template<typename T>
  T* alloc(size_t size) {
    cout << "Allocating " << size << " things!" << endl;
    return new T[size];
  }
};

int main() {
  auto my_new = New();
  auto myslice = Slice<int>(my_new, 10, 10);
  cout << "myslice: " << string(myslice) << endl;
  auto myslice2 = append(my_new, myslice, 1);
  // cout << "myslice: " << string(myslice2) << endl;
  // auto myslice3 = append(my_new, myslice, 2);
  // cout << "myslice: " << string(myslice3) << endl;
  // auto myslice4 = Slice<int>(my_new, 10, 10);
  // auto myslice5 = append(my_new, myslice2, 7);
  // auto myslice6 = append(my_new, myslice2, 8);
  // auto myslice7 = append(my_new, myslice2, 9);
  // cout << "myslice2: " << string(myslice7) << endl;

  // auto myslice8 = append(my_new, myslice, myslice2);
  // cout << "myslice: " << string(myslice8) << endl;

  return 0;
}<|endoftext|>


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

#include "TrackerThread.h"
#include "FilterDistortion.h"

#include "../base/Logger.h"
#include "../base/ProfilingZone.h"
#include "../base/ScopeTimer.h"

#include "../graphics/Filter.h"
#include "../graphics/Filterfill.h"
#include "../graphics/FilterHighpass.h"
#include "../graphics/FilterFastBandpass.h"
#include "../graphics/FilterBlur.h"
#include "../graphics/FilterGauss.h"

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

using namespace std;

namespace avg {
static ProfilingZone ProfilingZoneCapture ("Capture");
static ProfilingZone ProfilingZoneTracker ("Tracker");
static ProfilingZone ProfilingZoneHistory ("History");
static ProfilingZone ProfilingZoneDistort ("Distort");
static ProfilingZone ProfilingZoneHistogram ("Histogram");
static ProfilingZone ProfilingZoneBandpass ("Bandpass");
static ProfilingZone ProfilingZoneComps("ConnectedComps");
static ProfilingZone ProfilingZoneUpdate("Update");
static ProfilingZone ProfilingZoneDraw("Draw");

TrackerThread::TrackerThread(IntRect ROI,
        CameraPtr pCamera,
        BitmapPtr ppBitmaps[NUM_TRACKER_IMAGES],
        MutexPtr pMutex,
        CmdQueue& CmdQ,
        IBlobTarget *target,
        bool bSubtractHistory,
        TrackerConfig &config)
    : WorkerThread<TrackerThread>("Tracker", CmdQ),
      m_TouchThreshold(0),
      m_TrackThreshold(0),
      m_pMutex(pMutex),
      m_pCamera(pCamera),
      m_pTarget(target),
      m_bCreateDebugImages(false),
      m_bCreateFingerImage(false)
{
    if (bSubtractHistory) {
        m_pHistoryPreProcessor = HistoryPreProcessorPtr(
                new HistoryPreProcessor(ppBitmaps[1]->getSize(), 1,
                config.m_bBrighterRegions));
    }
    setBitmaps(ROI, ppBitmaps);
    m_pDistorter = FilterDistortionPtr(new FilterDistortion(m_pBitmaps[0]->getSize(),
            config.m_pTrafo));
}

TrackerThread::~TrackerThread()
{
}

bool TrackerThread::init()
{
// Done in TrackerEventSource::ctor to work around Leopard/libdc1394 threading issue.
//    m_pCamera->open();
    return true;
}

bool TrackerThread::work()
{
    BitmapPtr pCamBmp;
    {
        ScopeTimer Timer(ProfilingZoneCapture);
        pCamBmp = m_pCamera->getImage(true);
        BitmapPtr pTempBmp1;
        while (pTempBmp1 = m_pCamera->getImage(false)) {
            pCamBmp = pTempBmp1;
        }
    }
    if (pCamBmp) {
        ScopeTimer Timer(ProfilingZoneTracker);
        if (m_bCreateDebugImages) {
            boost::mutex::scoped_lock Lock(*m_pMutex);
            *(m_pBitmaps[TRACKER_IMG_CAMERA]) = *pCamBmp;
            ScopeTimer Timer(ProfilingZoneHistogram);
            drawHistogram(m_pBitmaps[TRACKER_IMG_HISTOGRAM], pCamBmp);
        }
        BitmapPtr pDistortedBmp;
        {
            ScopeTimer Timer(ProfilingZoneDistort);
            pDistortedBmp = m_pDistorter->apply(pCamBmp);
        }
        BitmapPtr pCroppedBmp(new Bitmap(*pDistortedBmp, m_ROI));
        if (m_bCreateDebugImages) {
            boost::mutex::scoped_lock Lock(*m_pMutex);
            m_pBitmaps[TRACKER_IMG_DISTORTED]->copyPixels(*pCroppedBmp);
        }
        if (m_pHistoryPreProcessor) {
            ScopeTimer Timer(ProfilingZoneHistory);
            m_pHistoryPreProcessor->applyInPlace(pCroppedBmp);
        }
        if (m_bCreateDebugImages) {
            boost::mutex::scoped_lock Lock(*m_pMutex);
            m_pBitmaps[TRACKER_IMG_NOHISTORY]->copyPixels(*pCroppedBmp);
        }
        {
            boost::mutex::scoped_lock Lock(*m_pMutex);
            if (m_bCreateFingerImage) {
                Pixel32 Black(0x00, 0x00, 0x00, 0x00);
                FilterFill<Pixel32>(Black).applyInPlace(
                        m_pBitmaps[TRACKER_IMG_FINGERS]);
            }
            BitmapPtr pBmpBandpass;
            if (m_TouchThreshold != 0) {
                {
                    ScopeTimer Timer(ProfilingZoneBandpass);
                    pBmpBandpass = FilterFastBandpass().apply(pCroppedBmp);
                }
                if (m_bCreateDebugImages) {
                    *(m_pBitmaps[TRACKER_IMG_HIGHPASS]) = *pBmpBandpass;
                }
            }
            calcBlobs(pCroppedBmp, pBmpBandpass);
        }
    }
    return true;
}

void TrackerThread::deinit()
{
    m_pCamera->close();
}

void TrackerThread::setConfig(TrackerConfig Config)
{
    if (Config.m_pTouch) {
        m_TouchThreshold = Config.m_pTouch->m_Threshold;
    } else {
        m_TouchThreshold = 0;
    }
    if (Config.m_pTrack) {
        m_TrackThreshold = Config.m_pTrack->m_Threshold;
        m_bTrackBrighter = Config.m_bBrighterRegions;
    } else {
        m_TrackThreshold = 0;
    }
    if(m_pHistoryPreProcessor) {
        m_pHistoryPreProcessor->setInterval(Config.m_HistoryUpdateInterval);
    }
    if (m_pTrafo != Config.m_pTrafo) {
        m_pDistorter = FilterDistortionPtr(new FilterDistortion(m_pBitmaps[0]->getSize(),
                Config.m_pTrafo));
        m_pTrafo = Config.m_pTrafo;
    }
    if (int(m_pCamera->getFeature("brightness")) != Config.m_Brightness ||
             int(m_pCamera->getFeature("gamma")) != Config.m_Gamma ||
             int(m_pCamera->getFeature("gain")) != Config.m_Gain ||
             int(m_pCamera->getFeature("shutter")) != Config.m_Shutter)
    {
        m_pHistoryPreProcessor->reset();
    }

    m_pCamera->setFeature("brightness", Config.m_Brightness);
    m_pCamera->setFeature("gamma", Config.m_Gamma);
    m_pCamera->setFeature("gain", Config.m_Gain);
    m_pCamera->setFeature("shutter", Config.m_Shutter);

    m_bCreateDebugImages = Config.m_bCreateDebugImages;
    m_bCreateFingerImage = Config.m_bCreateFingerImage;
}

void TrackerThread::setBitmaps(IntRect ROI, BitmapPtr ppBitmaps[NUM_TRACKER_IMAGES])
{
    m_ROI = ROI;
    for (int i=0; i<NUM_TRACKER_IMAGES; i++) {
        m_pBitmaps[i] = ppBitmaps[i];
    }
    if (m_pHistoryPreProcessor) {
        m_pHistoryPreProcessor = HistoryPreProcessorPtr(
                new HistoryPreProcessor(ROI.size(),
                        m_pHistoryPreProcessor->getInterval(), m_bTrackBrighter));
    }
}

void TrackerThread::resetHistory()
{
    if(m_pHistoryPreProcessor)
        m_pHistoryPreProcessor->reset();
}

void TrackerThread::drawHistogram(BitmapPtr pDestBmp, BitmapPtr pSrcBmp)
{
    HistogramPtr pHist = pSrcBmp->getHistogram(3);
    assert(pDestBmp->getPixelFormat() == I8);
    // Normalize Histogram to 0..255
    int Max1 = 0;
    int Max2 = 0;
    for (int i=0; i<256; ++i) {
        if ((*pHist)[i] > Max1) {
            Max2 = Max1;
            Max1 = (*pHist)[i];
        } else if ((*pHist)[i] > Max2) {
            Max2 = (*pHist)[i];
        }
    }
    if (Max2== 0) {
        Max2= 1;
    }
    for (int i=0; i<256; ++i) {
        (*pHist)[i] = int((*pHist)[i]*256.0/Max2)+1;
    }

    FilterFill<Pixel8>(0).applyInPlace(pDestBmp);
    int Width = pDestBmp->getSize().x;
    int Stride = pDestBmp->getStride();
    int EndRow = 256;
    if (pDestBmp->getSize().y < 256) {
        EndRow = pDestBmp->getSize().y;
    }
    for (int i=0; i<EndRow; ++i) {
        int StartCol =Width-(*pHist)[i];
        if (StartCol < 0) {
            StartCol = 0;
        }
        unsigned char * pDest = pDestBmp->getPixels()+Stride*i+StartCol;
        memset(pDest, 255, Width-StartCol);
    }
}

void TrackerThread::calcBlobs(BitmapPtr pTrackBmp, BitmapPtr pTouchBmp) {
    BlobVectorPtr pTrackComps;
    BlobVectorPtr pTouchComps;
    {
        ScopeTimer Timer(ProfilingZoneComps);
        pTrackComps = connected_components(pTrackBmp, m_TrackThreshold);
        pTouchComps = connected_components(pTouchBmp, m_TouchThreshold);
    }
    //    AVG_TRACE(Logger::EVENTS2, "connected components found "<<comps->size()<<" blobs.");
    //feed the IBlobTarget
    BitmapPtr pDestBmp;
    if (m_bCreateFingerImage) {
        pDestBmp = m_pBitmaps[TRACKER_IMG_FINGERS];
    }
    {
        ScopeTimer Timer(ProfilingZoneUpdate);
        m_pTarget->update(pTrackComps, pTrackBmp, m_TrackThreshold,
                pTouchComps, pTouchBmp, m_TouchThreshold, pDestBmp);
    }
}

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

#include "TrackerThread.h"
#include "FilterDistortion.h"

#include "../base/Logger.h"
#include "../base/ProfilingZone.h"
#include "../base/ScopeTimer.h"

#include "../graphics/Filter.h"
#include "../graphics/Filterfill.h"
#include "../graphics/FilterHighpass.h"
#include "../graphics/FilterFastBandpass.h"
#include "../graphics/FilterBlur.h"
#include "../graphics/FilterGauss.h"

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

using namespace std;

namespace avg {
static ProfilingZone ProfilingZoneCapture ("Capture");
static ProfilingZone ProfilingZoneTracker ("Tracker");
static ProfilingZone ProfilingZoneHistory ("History");
static ProfilingZone ProfilingZoneDistort ("Distort");
static ProfilingZone ProfilingZoneHistogram ("Histogram");
static ProfilingZone ProfilingZoneBandpass ("Bandpass");
static ProfilingZone ProfilingZoneComps("ConnectedComps");
static ProfilingZone ProfilingZoneUpdate("Update");
static ProfilingZone ProfilingZoneDraw("Draw");

TrackerThread::TrackerThread(IntRect ROI,
        CameraPtr pCamera,
        BitmapPtr ppBitmaps[NUM_TRACKER_IMAGES],
        MutexPtr pMutex,
        CmdQueue& CmdQ,
        IBlobTarget *target,
        bool bSubtractHistory,
        TrackerConfig &config)
    : WorkerThread<TrackerThread>("Tracker", CmdQ),
      m_TouchThreshold(0),
      m_TrackThreshold(0),
      m_pMutex(pMutex),
      m_pCamera(pCamera),
      m_pTarget(target),
      m_bCreateDebugImages(false),
      m_bCreateFingerImage(false)
{
    if (bSubtractHistory) {
        m_pHistoryPreProcessor = HistoryPreProcessorPtr(
                new HistoryPreProcessor(ppBitmaps[1]->getSize(), 1,
                config.m_bBrighterRegions));
    }
    m_bTrackBrighter = config.m_bBrighterRegions;
    setBitmaps(ROI, ppBitmaps);
    m_pDistorter = FilterDistortionPtr(new FilterDistortion(m_pBitmaps[0]->getSize(),
            config.m_pTrafo));
}

TrackerThread::~TrackerThread()
{
}

bool TrackerThread::init()
{
// Done in TrackerEventSource::ctor to work around Leopard/libdc1394 threading issue.
//    m_pCamera->open();
    return true;
}

bool TrackerThread::work()
{
    BitmapPtr pCamBmp;
    {
        ScopeTimer Timer(ProfilingZoneCapture);
        pCamBmp = m_pCamera->getImage(true);
        BitmapPtr pTempBmp1;
        while (pTempBmp1 = m_pCamera->getImage(false)) {
            pCamBmp = pTempBmp1;
        }
    }
    if (pCamBmp) {
        ScopeTimer Timer(ProfilingZoneTracker);
        if (m_bCreateDebugImages) {
            boost::mutex::scoped_lock Lock(*m_pMutex);
            *(m_pBitmaps[TRACKER_IMG_CAMERA]) = *pCamBmp;
            ScopeTimer Timer(ProfilingZoneHistogram);
            drawHistogram(m_pBitmaps[TRACKER_IMG_HISTOGRAM], pCamBmp);
        }
        BitmapPtr pDistortedBmp;
        {
            ScopeTimer Timer(ProfilingZoneDistort);
            pDistortedBmp = m_pDistorter->apply(pCamBmp);
        }
        BitmapPtr pCroppedBmp(new Bitmap(*pDistortedBmp, m_ROI));
        if (m_bCreateDebugImages) {
            boost::mutex::scoped_lock Lock(*m_pMutex);
            m_pBitmaps[TRACKER_IMG_DISTORTED]->copyPixels(*pCroppedBmp);
        }
        if (m_pHistoryPreProcessor) {
            ScopeTimer Timer(ProfilingZoneHistory);
            m_pHistoryPreProcessor->applyInPlace(pCroppedBmp);
        }
        if (m_bCreateDebugImages) {
            boost::mutex::scoped_lock Lock(*m_pMutex);
            m_pBitmaps[TRACKER_IMG_NOHISTORY]->copyPixels(*pCroppedBmp);
        }
        {
            boost::mutex::scoped_lock Lock(*m_pMutex);
            if (m_bCreateFingerImage) {
                Pixel32 Black(0x00, 0x00, 0x00, 0x00);
                FilterFill<Pixel32>(Black).applyInPlace(
                        m_pBitmaps[TRACKER_IMG_FINGERS]);
            }
            BitmapPtr pBmpBandpass;
            if (m_TouchThreshold != 0) {
                {
                    ScopeTimer Timer(ProfilingZoneBandpass);
                    pBmpBandpass = FilterFastBandpass().apply(pCroppedBmp);
                }
                if (m_bCreateDebugImages) {
                    *(m_pBitmaps[TRACKER_IMG_HIGHPASS]) = *pBmpBandpass;
                }
            }
            calcBlobs(pCroppedBmp, pBmpBandpass);
        }
    }
    return true;
}

void TrackerThread::deinit()
{
    m_pCamera->close();
}

void TrackerThread::setConfig(TrackerConfig Config)
{
    if (Config.m_pTouch) {
        m_TouchThreshold = Config.m_pTouch->m_Threshold;
    } else {
        m_TouchThreshold = 0;
    }
    if (Config.m_pTrack) {
        m_TrackThreshold = Config.m_pTrack->m_Threshold;
        m_bTrackBrighter = Config.m_bBrighterRegions;
    } else {
        m_TrackThreshold = 0;
    }
    if(m_pHistoryPreProcessor) {
        m_pHistoryPreProcessor->setInterval(Config.m_HistoryUpdateInterval);
    }
    if (m_pTrafo != Config.m_pTrafo) {
        m_pDistorter = FilterDistortionPtr(new FilterDistortion(m_pBitmaps[0]->getSize(),
                Config.m_pTrafo));
        m_pTrafo = Config.m_pTrafo;
    }
    if (int(m_pCamera->getFeature("brightness")) != Config.m_Brightness ||
             int(m_pCamera->getFeature("gamma")) != Config.m_Gamma ||
             int(m_pCamera->getFeature("gain")) != Config.m_Gain ||
             int(m_pCamera->getFeature("shutter")) != Config.m_Shutter)
    {
        m_pHistoryPreProcessor->reset();
    }

    m_pCamera->setFeature("brightness", Config.m_Brightness);
    m_pCamera->setFeature("gamma", Config.m_Gamma);
    m_pCamera->setFeature("gain", Config.m_Gain);
    m_pCamera->setFeature("shutter", Config.m_Shutter);

    m_bCreateDebugImages = Config.m_bCreateDebugImages;
    m_bCreateFingerImage = Config.m_bCreateFingerImage;
}

void TrackerThread::setBitmaps(IntRect ROI, BitmapPtr ppBitmaps[NUM_TRACKER_IMAGES])
{
    m_ROI = ROI;
    for (int i=0; i<NUM_TRACKER_IMAGES; i++) {
        m_pBitmaps[i] = ppBitmaps[i];
    }
    if (m_pHistoryPreProcessor) {
        m_pHistoryPreProcessor = HistoryPreProcessorPtr(
                new HistoryPreProcessor(ROI.size(),
                        m_pHistoryPreProcessor->getInterval(), m_bTrackBrighter));
    }
}

void TrackerThread::resetHistory()
{
    if(m_pHistoryPreProcessor)
        m_pHistoryPreProcessor->reset();
}

void TrackerThread::drawHistogram(BitmapPtr pDestBmp, BitmapPtr pSrcBmp)
{
    HistogramPtr pHist = pSrcBmp->getHistogram(3);
    assert(pDestBmp->getPixelFormat() == I8);
    // Normalize Histogram to 0..255
    int Max1 = 0;
    int Max2 = 0;
    for (int i=0; i<256; ++i) {
        if ((*pHist)[i] > Max1) {
            Max2 = Max1;
            Max1 = (*pHist)[i];
        } else if ((*pHist)[i] > Max2) {
            Max2 = (*pHist)[i];
        }
    }
    if (Max2== 0) {
        Max2= 1;
    }
    for (int i=0; i<256; ++i) {
        (*pHist)[i] = int((*pHist)[i]*256.0/Max2)+1;
    }

    FilterFill<Pixel8>(0).applyInPlace(pDestBmp);
    int Width = pDestBmp->getSize().x;
    int Stride = pDestBmp->getStride();
    int EndRow = 256;
    if (pDestBmp->getSize().y < 256) {
        EndRow = pDestBmp->getSize().y;
    }
    for (int i=0; i<EndRow; ++i) {
        int StartCol =Width-(*pHist)[i];
        if (StartCol < 0) {
            StartCol = 0;
        }
        unsigned char * pDest = pDestBmp->getPixels()+Stride*i+StartCol;
        memset(pDest, 255, Width-StartCol);
    }
}

void TrackerThread::calcBlobs(BitmapPtr pTrackBmp, BitmapPtr pTouchBmp) {
    BlobVectorPtr pTrackComps;
    BlobVectorPtr pTouchComps;
    {
        ScopeTimer Timer(ProfilingZoneComps);
        pTrackComps = connected_components(pTrackBmp, m_TrackThreshold);
        pTouchComps = connected_components(pTouchBmp, m_TouchThreshold);
    }
    //    AVG_TRACE(Logger::EVENTS2, "connected components found "<<comps->size()<<" blobs.");
    //feed the IBlobTarget
    BitmapPtr pDestBmp;
    if (m_bCreateFingerImage) {
        pDestBmp = m_pBitmaps[TRACKER_IMG_FINGERS];
    }
    {
        ScopeTimer Timer(ProfilingZoneUpdate);
        m_pTarget->update(pTrackComps, pTrackBmp, m_TrackThreshold,
                pTouchComps, pTouchBmp, m_TouchThreshold, pDestBmp);
    }
}

}
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#ifndef GUARD_MIOPEN_LOGGER_HPP
#define GUARD_MIOPEN_LOGGER_HPP

#include <array>
#include <iostream>
#include <miopen/each_args.hpp>
#include <type_traits>

// See https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
#define MIOPEN_PP_CAT(x, y) MIOPEN_PP_PRIMITIVE_CAT(x, y)
#define MIOPEN_PP_PRIMITIVE_CAT(x, y) x##y

#define MIOPEN_PP_IIF(c) MIOPEN_PP_PRIMITIVE_CAT(MIOPEN_PP_IIF_, c)
#define MIOPEN_PP_IIF_0(t, ...) __VA_ARGS__
#define MIOPEN_PP_IIF_1(t, ...) t

#define MIOPEN_PP_IS_PAREN(x) MIOPEN_PP_IS_PAREN_CHECK(MIOPEN_PP_IS_PAREN_PROBE x)
#define MIOPEN_PP_IS_PAREN_CHECK(...) MIOPEN_PP_IS_PAREN_CHECK_N(__VA_ARGS__, 0)
#define MIOPEN_PP_IS_PAREN_PROBE(...) ~, 1,
#define MIOPEN_PP_IS_PAREN_CHECK_N(x, n, ...) n

#define MIOPEN_PP_EAT(...)
#define MIOPEN_PP_EXPAND(...) __VA_ARGS__
#define MIOPEN_PP_COMMA(...) ,

#define MIOPEN_PP_TRANSFORM_ARGS(m, ...)                                 \
    MIOPEN_PP_EXPAND(MIOPEN_PP_PRIMITIVE_TRANSFORM_ARGS(m,               \
                                                        MIOPEN_PP_COMMA, \
                                                        __VA_ARGS__,     \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        ()))

#define MIOPEN_PP_EACH_ARGS(m, ...)                                    \
    MIOPEN_PP_EXPAND(MIOPEN_PP_PRIMITIVE_TRANSFORM_ARGS(m,             \
                                                        MIOPEN_PP_EAT, \
                                                        __VA_ARGS__,   \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        ()))

#define MIOPEN_PP_PRIMITIVE_TRANSFORM_ARGS(                                              \
    m, delim, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, ...) \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x0)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x1)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x1)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x2)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x2)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x3)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x3)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x4)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x4)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x5)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x5)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x6)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x6)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x7)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x7)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x8)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x8)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x9)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x9)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x10)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x10)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x11)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x11)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x12)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x12)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x13)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x13)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x14)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x14)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x15) MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x15)

#define MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x) \
    MIOPEN_PP_IIF(MIOPEN_PP_IS_PAREN(x))(MIOPEN_PP_EAT, m)(x)

namespace miopen {

template <class Range>
std::ostream& LogRange(std::ostream& os, Range&& r, std::string delim)
{
    bool first = true;
    for(auto&& x : r)
    {
        if(first)
            first = false;
        else
            os << delim;
        os << x;
    }
    return os;
}

template <class T, class... Ts>
std::array<T, sizeof...(Ts) + 1> make_array(T x, Ts... xs)
{
    return {{x, xs...}};
}

#define MIOPEN_LOG_ENUM_EACH(x) std::pair<std::string, decltype(x)>(#x, x)
#ifdef _MSC_VER
#define MIOPEN_LOG_ENUM(os, ...) os
#else
#define MIOPEN_LOG_ENUM(os, x, ...) \
    miopen::LogEnum(os, x, make_array(MIOPEN_PP_TRANSFORM_ARGS(MIOPEN_LOG_ENUM_EACH, __VA_ARGS__)))
#endif

template <class T, class Range>
std::ostream& LogEnum(std::ostream& os, T x, Range&& values)
{
    for(auto&& p : values)
    {
        if(p.second == x)
        {
            os << p.first;
            return os;
        }
    }
    os << "Unknown: " << x;
    return os;
}

enum LoggingLevel
{
    Default = 0, // WARNING for Release builds, INFO for Debug builds.
    Quiet,
    Fatal,
    Error,
    Warning,
    Info,
    Info2,
    Trace // E.g. messages output by MIOPEN_LOG_FUNCTION).
};

const char* LoggingLevelToCString(enum LoggingLevel level);

std::string PlatformName();

/// \return true if level is enabled.
/// \param level - one of the values defined in LoggingLevel.
int IsLogging(int level = LoggingLevel::Error);

template <class T>
auto LogObjImpl(T* x) -> decltype(get_object(*x))
{
    return get_object(*x);
}

inline void* LogObjImpl(void* x) { return x; }

inline const void* LogObjImpl(const void* x) { return x; }

#ifndef _MSC_VER
template <class T, typename std::enable_if<(std::is_pointer<T>{}), int>::type = 0>
std::ostream& LogParam(std::ostream& os, std::string name, const T& x)
{
    os << name << " = ";
    if(x == nullptr)
        os << "nullptr";
    else
        os << LogObjImpl(x);
    return os;
}

template <class T, typename std::enable_if<(not std::is_pointer<T>{}), int>::type = 0>
std::ostream& LogParam(std::ostream& os, std::string name, const T& x)
{
    os << name << " = " << get_object(x);
    return os;
}
#define MIOPEN_LOG_FUNCTION_EACH(param) miopen::LogParam(std::cerr, #param, param) << std::endl;

#define MIOPEN_LOG_FUNCTION(...)                                   \
    if(miopen::IsLogging(miopen::LoggingLevel::Trace))             \
    {                                                              \
        std::cerr << miopen::PlatformName() << ": " << __PRETTY_FUNCTION__ << "{" << std::endl;      \
        MIOPEN_PP_EACH_ARGS(MIOPEN_LOG_FUNCTION_EACH, __VA_ARGS__) \
        std::cerr << "}" << std::endl;                             \
    }
#else
#define MIOPEN_LOG_FUNCTION(...)
#endif

/// \todo __PRETTY_FUNCTION__ is too verbose, __func_ it too short.
/// Shall we add filename (no path, no ext) prior __func__.
#define MIOPEN_LOG(level, ...)                                                                   \
    do                                                                                \
    {                                                                                \
        if(miopen::IsLogging(level))                                                             \
        {                                                                                \
            std::cerr << miopen::PlatformName() << ": " << LoggingLevelToCString(level) << " [" << __func__ << "] " << __VA_ARGS__ \
                      << std::endl;                                                              \
        }                                                                                \
    } while(false)

} // namespace miopen

#endif
<commit_msg>Formatting<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#ifndef GUARD_MIOPEN_LOGGER_HPP
#define GUARD_MIOPEN_LOGGER_HPP

#include <array>
#include <iostream>
#include <miopen/each_args.hpp>
#include <type_traits>

// See https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
#define MIOPEN_PP_CAT(x, y) MIOPEN_PP_PRIMITIVE_CAT(x, y)
#define MIOPEN_PP_PRIMITIVE_CAT(x, y) x##y

#define MIOPEN_PP_IIF(c) MIOPEN_PP_PRIMITIVE_CAT(MIOPEN_PP_IIF_, c)
#define MIOPEN_PP_IIF_0(t, ...) __VA_ARGS__
#define MIOPEN_PP_IIF_1(t, ...) t

#define MIOPEN_PP_IS_PAREN(x) MIOPEN_PP_IS_PAREN_CHECK(MIOPEN_PP_IS_PAREN_PROBE x)
#define MIOPEN_PP_IS_PAREN_CHECK(...) MIOPEN_PP_IS_PAREN_CHECK_N(__VA_ARGS__, 0)
#define MIOPEN_PP_IS_PAREN_PROBE(...) ~, 1,
#define MIOPEN_PP_IS_PAREN_CHECK_N(x, n, ...) n

#define MIOPEN_PP_EAT(...)
#define MIOPEN_PP_EXPAND(...) __VA_ARGS__
#define MIOPEN_PP_COMMA(...) ,

#define MIOPEN_PP_TRANSFORM_ARGS(m, ...)                                 \
    MIOPEN_PP_EXPAND(MIOPEN_PP_PRIMITIVE_TRANSFORM_ARGS(m,               \
                                                        MIOPEN_PP_COMMA, \
                                                        __VA_ARGS__,     \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        (),              \
                                                        ()))

#define MIOPEN_PP_EACH_ARGS(m, ...)                                    \
    MIOPEN_PP_EXPAND(MIOPEN_PP_PRIMITIVE_TRANSFORM_ARGS(m,             \
                                                        MIOPEN_PP_EAT, \
                                                        __VA_ARGS__,   \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        (),            \
                                                        ()))

#define MIOPEN_PP_PRIMITIVE_TRANSFORM_ARGS(                                              \
    m, delim, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, ...) \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x0)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x1)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x1)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x2)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x2)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x3)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x3)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x4)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x4)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x5)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x5)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x6)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x6)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x7)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x7)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x8)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x8)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x9)                                         \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x9)                                             \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x10)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x10)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x11)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x11)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x12)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x12)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x13)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x13)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x14)                                        \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x14)                                            \
    MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(delim, x15) MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x15)

#define MIOPEN_PP_PRIMITIVE_TRANSFORM_ARG(m, x) \
    MIOPEN_PP_IIF(MIOPEN_PP_IS_PAREN(x))(MIOPEN_PP_EAT, m)(x)

namespace miopen {

template <class Range>
std::ostream& LogRange(std::ostream& os, Range&& r, std::string delim)
{
    bool first = true;
    for(auto&& x : r)
    {
        if(first)
            first = false;
        else
            os << delim;
        os << x;
    }
    return os;
}

template <class T, class... Ts>
std::array<T, sizeof...(Ts) + 1> make_array(T x, Ts... xs)
{
    return {{x, xs...}};
}

#define MIOPEN_LOG_ENUM_EACH(x) std::pair<std::string, decltype(x)>(#x, x)
#ifdef _MSC_VER
#define MIOPEN_LOG_ENUM(os, ...) os
#else
#define MIOPEN_LOG_ENUM(os, x, ...) \
    miopen::LogEnum(os, x, make_array(MIOPEN_PP_TRANSFORM_ARGS(MIOPEN_LOG_ENUM_EACH, __VA_ARGS__)))
#endif

template <class T, class Range>
std::ostream& LogEnum(std::ostream& os, T x, Range&& values)
{
    for(auto&& p : values)
    {
        if(p.second == x)
        {
            os << p.first;
            return os;
        }
    }
    os << "Unknown: " << x;
    return os;
}

enum LoggingLevel
{
    Default = 0, // WARNING for Release builds, INFO for Debug builds.
    Quiet,
    Fatal,
    Error,
    Warning,
    Info,
    Info2,
    Trace // E.g. messages output by MIOPEN_LOG_FUNCTION).
};

const char* LoggingLevelToCString(enum LoggingLevel level);

std::string PlatformName();

/// \return true if level is enabled.
/// \param level - one of the values defined in LoggingLevel.
int IsLogging(int level = LoggingLevel::Error);

template <class T>
auto LogObjImpl(T* x) -> decltype(get_object(*x))
{
    return get_object(*x);
}

inline void* LogObjImpl(void* x) { return x; }

inline const void* LogObjImpl(const void* x) { return x; }

#ifndef _MSC_VER
template <class T, typename std::enable_if<(std::is_pointer<T>{}), int>::type = 0>
std::ostream& LogParam(std::ostream& os, std::string name, const T& x)
{
    os << name << " = ";
    if(x == nullptr)
        os << "nullptr";
    else
        os << LogObjImpl(x);
    return os;
}

template <class T, typename std::enable_if<(not std::is_pointer<T>{}), int>::type = 0>
std::ostream& LogParam(std::ostream& os, std::string name, const T& x)
{
    os << name << " = " << get_object(x);
    return os;
}
#define MIOPEN_LOG_FUNCTION_EACH(param) miopen::LogParam(std::cerr, #param, param) << std::endl;

#define MIOPEN_LOG_FUNCTION(...)                                                                \
    if(miopen::IsLogging(miopen::LoggingLevel::Trace))                                          \
    {                                                                                \
        std::cerr << miopen::PlatformName() << ": " << __PRETTY_FUNCTION__ << "{" << std::endl; \
        MIOPEN_PP_EACH_ARGS(MIOPEN_LOG_FUNCTION_EACH, __VA_ARGS__)                              \
        std::cerr << "}" << std::endl;                                                          \
    }
#else
#define MIOPEN_LOG_FUNCTION(...)
#endif

/// \todo __PRETTY_FUNCTION__ is too verbose, __func_ it too short.
/// Shall we add filename (no path, no ext) prior __func__.
#define MIOPEN_LOG(level, ...)                                                                  \
    do                                                                                \
    {                                                                                \
        if(miopen::IsLogging(level))                                                            \
        {                                                                                \
            std::cerr << miopen::PlatformName() << ": " << LoggingLevelToCString(level) << " [" \
                      << __func__ << "] " << __VA_ARGS__ << std::endl;                          \
        }                                                                                \
    } while(false)

} // namespace miopen

#endif
<|endoftext|>


<commit_before>#include "address_space.h"
#include <iostream>
#include <gasnet.h>
#include "common.h"

int AddressSpace::init(int *argc, char ***argv)
{
  GASNET_SAFE(gasnet_init(argc, argv));

  size_t segsz = gasnet_getMaxLocalSegmentSize();
  GASNET_SAFE(gasnet_attach(NULL, 0, segsz, 0));

  gasnet_seginfo_t segments[gasnet_nodes()];
  GASNET_SAFE(gasnet_getSegmentInfo(segments, gasnet_nodes()));

  if (gasnet_mynode()) {
    gasnet_barrier_notify(0, GASNET_BARRIERFLAG_ANONYMOUS);
    gasnet_barrier_wait(0, GASNET_BARRIERFLAG_ANONYMOUS);
    gasnet_exit(0);
    return 0;
  }

  for (int i = 0; i < gasnet_nodes(); i++) {
    Segment seg;
    seg.addr = (size_t)segments[i].addr;
    seg.len = segments[i].size;

    Node node;
    node.segment = seg;
    node.node = i;

    nodes.push_back(node);

    std::cout << "node-%02d: segment: " <<
      segments[i].size << "/" << segments[i].addr << std::endl;
  }

  return 0;
}

void AddressSpace::write(int node, void *dst, void *src, size_t len)
{
  gasnet_put_bulk(nodes[node].node, dst, src, len);
}

void AddressSpace::read(void *dest, int node, void *src, size_t len)
{
  gasnet_get_bulk(dest, nodes[node].node, src, len);
}
<commit_msg>gasnet: support gasnet everything<commit_after>#include "address_space.h"
#include <cassert>
#include <iostream>
#include <sys/mman.h>
#include <gasnet.h>
#include <gasnet_tools.h>
#include "common.h"

#ifdef GASNET_SEGMENT_EVERYTHING

static gasnet_seginfo_t *segments_ptr;
static int seginfo_done;
static gasnet_hsl_t seginfo_lock;

#define AM_SEGINFO 128

static void AM_seginfo(gasnet_token_t token, void *buf, size_t nbytes)
{
  gasnet_node_t src;
  GASNET_SAFE(gasnet_AMGetMsgSource(token, &src));

  gasnet_seginfo_t contrib;
  assert(nbytes == sizeof(contrib));
  memcpy(&contrib, buf, sizeof(contrib));

  // barrier: seginfo_done is checked without lock
  gasnett_local_wmb();

  gasnet_hsl_lock(&seginfo_lock);
  segments_ptr[src] = contrib;
  seginfo_done++;
  gasnet_hsl_unlock(&seginfo_lock);
}

int AddressSpace::init(int *argc, char ***argv)
{
  std::cout << "gasnet segment = everything" << std::endl;

  GASNET_SAFE(gasnet_init(argc, argv));

  // handler for sending segment info to rank 0
  gasnet_handlerentry_t handlers[1];
  handlers[0].index = AM_SEGINFO;
  handlers[0].fnptr = (void(*)())AM_seginfo;

  // segment info ignored for gasnet-everything
  GASNET_SAFE(gasnet_attach(handlers, 1, 0, 0));

  gasnet_seginfo_t segments[gasnet_nodes()];
  GASNET_SAFE(gasnet_getSegmentInfo(segments, gasnet_nodes()));

  gasnet_hsl_init(&seginfo_lock);
  segments_ptr = segments;
  seginfo_done = 0;

  // synchronized everyone before sending AMs so rank 0 initialization of
  // segments structure above doesn't race. could also hold lock above...
  gasnet_barrier_notify(0, GASNET_BARRIERFLAG_ANONYMOUS);
  gasnet_barrier_wait(0, GASNET_BARRIERFLAG_ANONYMOUS);

  /*
   * currently rank 0 also contributes memory. We want to avoid this in the
   * future because rank 0 should have a large kernel cache for the FUSE
   * mount.
   */
  const size_t size = 1ULL << 30;
  void *data = mmap(NULL, size, PROT_READ|PROT_WRITE,
      MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  assert(data != MAP_FAILED);

  // notify rank 0 of contribution (rank 0 sends to self)
  gasnet_seginfo_t contrib;
  contrib.addr = data;
  contrib.size = size;
  GASNET_SAFE(gasnet_AMRequestMedium0(0, AM_SEGINFO,
        &contrib, sizeof(contrib)));

  // everyone but rank 0 snoozes now
  if (gasnet_mynode()) {
    gasnet_barrier_notify(0, GASNET_BARRIERFLAG_ANONYMOUS);
    gasnet_barrier_wait(0, GASNET_BARRIERFLAG_ANONYMOUS);
    gasnet_exit(0);
    return 0;
  }

  // wait for nodes to report on contribution
  GASNET_BLOCKUNTIL((seginfo_done == gasnet_nodes()));

  gasnet_hsl_lock(&seginfo_lock);
  assert(seginfo_done == gasnet_nodes());

  for (int i = 0; i < gasnet_nodes(); i++) {
    Segment seg;
    seg.addr = (size_t)segments[i].addr;
    seg.len = segments[i].size;

    Node node;
    node.segment = seg;
    node.node = i;

    nodes.push_back(node);

    std::cout << "node-%02d: segment: " <<
      segments[i].size << "/" << segments[i].addr << std::endl;
  }

  gasnet_hsl_unlock(&seginfo_lock);

  return 0;
}
#else
int AddressSpace::init(int *argc, char ***argv)
{
  std::cout << "gasnet segment = fast|large" << std::endl;

  GASNET_SAFE(gasnet_init(argc, argv));

  size_t segsz = gasnet_getMaxLocalSegmentSize();
  GASNET_SAFE(gasnet_attach(NULL, 0, segsz, 0));

  gasnet_seginfo_t segments[gasnet_nodes()];
  GASNET_SAFE(gasnet_getSegmentInfo(segments, gasnet_nodes()));

  if (gasnet_mynode()) {
    gasnet_barrier_notify(0, GASNET_BARRIERFLAG_ANONYMOUS);
    gasnet_barrier_wait(0, GASNET_BARRIERFLAG_ANONYMOUS);
    gasnet_exit(0);
    return 0;
  }

  for (int i = 0; i < gasnet_nodes(); i++) {
    Segment seg;
    seg.addr = (size_t)segments[i].addr;
    seg.len = segments[i].size;

    Node node;
    node.segment = seg;
    node.node = i;

    nodes.push_back(node);

    std::cout << "node-%02d: segment: " <<
      segments[i].size << "/" << segments[i].addr << std::endl;
  }

  return 0;
}
#endif

void AddressSpace::write(int node, void *dst, void *src, size_t len)
{
  gasnet_put_bulk(nodes[node].node, dst, src, len);
}

void AddressSpace::read(void *dest, int node, void *src, size_t len)
{
  gasnet_get_bulk(dest, nodes[node].node, src, len);
}
<|endoftext|>