<commit_before>#pragma once

#include "types.hh"
#include "serialise.hh"

namespace nix {

/* dumpPath creates a Nix archive of the specified path.  The format
   is as follows:

   IF path points to a REGULAR FILE:
     dump(path) = attrs(
       [ ("type", "regular")
       , ("contents", contents(path))
       ])

   IF path points to a DIRECTORY:
     dump(path) = attrs(
       [ ("type", "directory")
       , ("entries", concat(map(f, sort(entries(path)))))
       ])
       where f(fn) = attrs(
         [ ("name", fn)
         , ("file", dump(path + "/" + fn))
         ])

   where:

     attrs(as) = concat(map(attr, as)) + encN(0)
     attrs((a, b)) = encS(a) + encS(b)

     encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary)

     encN(n) = 64-bit little-endian encoding of n.

     contents(path) = the contents of a regular file.

     sort(strings) = lexicographic sort by 8-bit value (strcmp).

     entries(path) = the entries of a directory, without `.' and
     `..'.

     `+' denotes string concatenation. */

struct PathFilter
{
    virtual ~PathFilter() { }
    virtual bool operator () (const Path & path) { return true; }
};

extern PathFilter defaultPathFilter;

void dumpPath(const Path & path, Sink & sink,
    PathFilter & filter = defaultPathFilter);

void dumpString(const std::string & s, Sink & sink);

/* FIXME: fix this API, it sucks. */
struct ParseSink
{
    virtual void createDirectory(const Path & path) { };

    virtual void createRegularFile(const Path & path) { };
    virtual void isExecutable() { };
    virtual void preallocateContents(unsigned long long size) { };
    virtual void receiveContents(unsigned char * data, unsigned int len) { };

    virtual void createSymlink(const Path & path, const string & target) { };
};

struct TeeSink : ParseSink
{
    TeeSource source;

    TeeSink(Source & source) : source(source) { }

    void preallocateContents(unsigned long long size) override
    {
        source.data->reserve(source.data->size() + size + 1024);
    };

};

void parseDump(ParseSink & sink, Source & source);

void restorePath(const Path & path, Source & source);

// FIXME: global variables are bad m'kay.
extern bool useCaseHack;

extern const std::string narVersionMagic1;

}
<commit_msg>Revert fa125b9b28bea25a4eeb4d39a71a481563127cb9<commit_after>#pragma once

#include "types.hh"
#include "serialise.hh"

namespace nix {

/* dumpPath creates a Nix archive of the specified path.  The format
   is as follows:

   IF path points to a REGULAR FILE:
     dump(path) = attrs(
       [ ("type", "regular")
       , ("contents", contents(path))
       ])

   IF path points to a DIRECTORY:
     dump(path) = attrs(
       [ ("type", "directory")
       , ("entries", concat(map(f, sort(entries(path)))))
       ])
       where f(fn) = attrs(
         [ ("name", fn)
         , ("file", dump(path + "/" + fn))
         ])

   where:

     attrs(as) = concat(map(attr, as)) + encN(0)
     attrs((a, b)) = encS(a) + encS(b)

     encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary)

     encN(n) = 64-bit little-endian encoding of n.

     contents(path) = the contents of a regular file.

     sort(strings) = lexicographic sort by 8-bit value (strcmp).

     entries(path) = the entries of a directory, without `.' and
     `..'.

     `+' denotes string concatenation. */

struct PathFilter
{
    virtual ~PathFilter() { }
    virtual bool operator () (const Path & path) { return true; }
};

extern PathFilter defaultPathFilter;

void dumpPath(const Path & path, Sink & sink,
    PathFilter & filter = defaultPathFilter);

void dumpString(const std::string & s, Sink & sink);

/* FIXME: fix this API, it sucks. */
struct ParseSink
{
    virtual void createDirectory(const Path & path) { };

    virtual void createRegularFile(const Path & path) { };
    virtual void isExecutable() { };
    virtual void preallocateContents(unsigned long long size) { };
    virtual void receiveContents(unsigned char * data, unsigned int len) { };

    virtual void createSymlink(const Path & path, const string & target) { };
};

struct TeeSink : ParseSink
{
    TeeSource source;

    TeeSink(Source & source) : source(source) { }
};

void parseDump(ParseSink & sink, Source & source);

void restorePath(const Path & path, Source & source);

// FIXME: global variables are bad m'kay.
extern bool useCaseHack;

extern const std::string narVersionMagic1;

}
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <sstream>

#include "analyzer.h"
#include "ast.h"
#include "compiler.h"
#include "debuginfo.h"
#include "disassembler.h"
#include "lexer.h"
#include "parser.h"
#include "pt_dump.h"
#include "support.h"

extern void compile_cli(CompilerSupport *support, const ast::Program *);
extern void compile_cpp(CompilerSupport *support, const ast::Program *);
extern void compile_js(CompilerSupport *support, const ast::Program *);
extern void compile_jvm(CompilerSupport *support, const ast::Program *);

struct {
    std::string name;
    CompileProc proc;
} Targets[] = {
    {"cli", compile_cli},
    {"cpp", compile_cpp},
    {"js", compile_js},
    {"jvm", compile_jvm},
};

int main(int argc, char *argv[])
{
    bool ignore_errors = false;
    bool listing = false;
    bool quiet = false;
    bool error_json = false;
    std::string target;
    CompileProc target_proc = nullptr;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s filename.neon\n", argv[0]);
        exit(1);
    }

    int a = 1;
    while (a < argc) {
        if (std::string(argv[a]) == "-i") {
            ignore_errors = true;
            a++;
            continue;
        }
        if (std::string(argv[a]) == "-d") {
            listing = true;
            a++;
            continue;
        }
        if (std::string(argv[a]) == "--json") {
            error_json = true;
            a++;
            continue;
        }
        if (std::string(argv[a]) == "-q") {
            quiet = true;
            a++;
            continue;
        }
        if (std::string(argv[a]) == "-t") {
            a++;
            if (a < argc) {
                target = argv[a];
                size_t i = 0;
                while (i < sizeof(Targets)/sizeof(Targets[0]) && target != Targets[i].name) {
                    i++;
                }
                if (i < sizeof(Targets)/sizeof(Targets[0])) {
                    target_proc = Targets[i].proc;
                } else {
                    std::cerr << "Unknown target: " << target << "\n";
                    exit(1);
                }
            }
            a++;
            continue;
        }

        std::string name = argv[a];
        std::string source_path;

        std::stringstream buf;
        if (name == "-") {
            if (not quiet) {
                std::cout << "Compiling stdin (no output file)";
            }
            buf << std::cin.rdbuf();
        } else {
            auto i = name.find_last_of("/:\\");
            if (i != std::string::npos) {
                source_path = name.substr(0, i+1);
            }
            if (not quiet) {
                std::cout << "Compiling " << name;
            }
            std::ifstream inf(name);
            buf << inf.rdbuf();
        }
        if (not quiet) {
            if (not target.empty()) {
                std::cout << " for target " << target;
            }
            std::cout << "...\n";
        }

        CompilerSupport compiler_support(source_path, target_proc);

        try {
            auto tokens = tokenize(name, buf.str());
            auto parsetree = parse(*tokens);
            auto ast = analyze(&compiler_support, parsetree.get());
            DebugInfo debug(name, buf.str());
            if (target_proc == nullptr) {
                auto bytecode = compile(ast, &debug);
                if (listing) {
                    disassemble(bytecode, std::cerr, &debug);
                }
                if (name != "-") {
                    std::ofstream outf(std::string(argv[a]) + "x", std::ios::binary);
                    outf.write(reinterpret_cast<const std::ofstream::char_type *>(bytecode.data()), bytecode.size());
                }
            } else {
                target_proc(&compiler_support, ast);
            }

        } catch (CompilerError *error) {
            if (error_json) {
                error->write_json(std::cerr);
            } else {
                error->write(std::cerr);
            }
            if (not ignore_errors) {
                exit(1);
            }
        }

        a++;
    }
}
<commit_msg>Rework option parsing to identify unknown options<commit_after>#include <fstream>
#include <iostream>
#include <sstream>

#include "analyzer.h"
#include "ast.h"
#include "compiler.h"
#include "debuginfo.h"
#include "disassembler.h"
#include "lexer.h"
#include "parser.h"
#include "pt_dump.h"
#include "support.h"

extern void compile_cli(CompilerSupport *support, const ast::Program *);
extern void compile_cpp(CompilerSupport *support, const ast::Program *);
extern void compile_js(CompilerSupport *support, const ast::Program *);
extern void compile_jvm(CompilerSupport *support, const ast::Program *);

struct {
    std::string name;
    CompileProc proc;
} Targets[] = {
    {"cli", compile_cli},
    {"cpp", compile_cpp},
    {"js", compile_js},
    {"jvm", compile_jvm},
};

int main(int argc, char *argv[])
{
    bool ignore_errors = false;
    bool listing = false;
    bool quiet = false;
    bool error_json = false;
    std::string target;
    CompileProc target_proc = nullptr;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s filename.neon\n", argv[0]);
        exit(1);
    }

    int a = 1;
    while (a < argc && argv[a][0] == '-' && argv[a][1] != '\0') {
        std::string arg = argv[a];
        if (arg == "-i") {
            ignore_errors = true;
        } else if (arg == "-d") {
            listing = true;
        } else if (arg == "--json") {
            error_json = true;
        } else if (arg == "-q") {
            quiet = true;
        } else if (arg == "-t") {
            a++;
            if (a < argc) {
                target = argv[a];
                size_t i = 0;
                while (i < sizeof(Targets)/sizeof(Targets[0]) && target != Targets[i].name) {
                    i++;
                }
                if (i < sizeof(Targets)/sizeof(Targets[0])) {
                    target_proc = Targets[i].proc;
                } else {
                    std::cerr << "Unknown target: " << target << "\n";
                    exit(1);
                }
            }
        } else {
            fprintf(stderr, "Unknown option: %s\n", arg.c_str());
            exit(1);
        }
        a++;
    }

    while (a < argc) {
        std::string name = argv[a];
        std::string source_path;

        std::stringstream buf;
        if (name == "-") {
            if (not quiet) {
                std::cout << "Compiling stdin (no output file)";
            }
            buf << std::cin.rdbuf();
        } else {
            auto i = name.find_last_of("/:\\");
            if (i != std::string::npos) {
                source_path = name.substr(0, i+1);
            }
            if (not quiet) {
                std::cout << "Compiling " << name;
            }
            std::ifstream inf(name);
            buf << inf.rdbuf();
        }
        if (not quiet) {
            if (not target.empty()) {
                std::cout << " for target " << target;
            }
            std::cout << "...\n";
        }

        CompilerSupport compiler_support(source_path, target_proc);

        try {
            auto tokens = tokenize(name, buf.str());
            auto parsetree = parse(*tokens);
            auto ast = analyze(&compiler_support, parsetree.get());
            DebugInfo debug(name, buf.str());
            if (target_proc == nullptr) {
                auto bytecode = compile(ast, &debug);
                if (listing) {
                    disassemble(bytecode, std::cerr, &debug);
                }
                if (name != "-") {
                    std::ofstream outf(std::string(argv[a]) + "x", std::ios::binary);
                    outf.write(reinterpret_cast<const std::ofstream::char_type *>(bytecode.data()), bytecode.size());
                }
            } else {
                target_proc(&compiler_support, ast);
            }

        } catch (CompilerError *error) {
            if (error_json) {
                error->write_json(std::cerr);
            } else {
                error->write(std::cerr);
            }
            if (not ignore_errors) {
                exit(1);
            }
        }

        a++;
    }
}
<|endoftext|>


<commit_before>/* <src/HttpWorker.cpp>
 *
 * This file is part of the x0 web server project and is released under GPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2013 Christian Parpart <trapni@gmail.com>
 */

#include <x0/http/HttpWorker.h>
#include <x0/http/HttpRequest.h>
#include <x0/http/HttpServer.h>
#include <x0/http/HttpConnection.h>
#include <x0/ServerSocket.h>
#include <x0/DebugLogger.h>

#include <algorithm>
#include <cstdarg>
#include <ev++.h>
#include <signal.h>
#include <pthread.h>

// XXX one a connection has been passed to a worker, it is *bound* to it.

#if 0//!defined(XZERO_NDEBUG)
//#	define TRACE(n, msg...) X0_DEBUG("worker", (n), msg)
#	define TRACE(n, msg...) log(Severity::debug ## n, msg)
#else
#	define TRACE(n, msg...) do {} while (0)
#endif

namespace x0 {

/*!
 * Creates an HTTP worker instance.
 *
 * \param server   the worker parents server instance
 * \param loop     the event loop to be used within this worker
 * \param id       unique ID within the server instance
 * \param threaded whether or not to spawn a thread to actually run this worker
 */
HttpWorker::HttpWorker(HttpServer& server, struct ev_loop *loop, unsigned int id, bool threaded) :
	id_(id),
	state_(Inactive),
	server_(server),
	loop_(loop),
	startupTime_(ev_now(loop_)),
	now_(),
	connectionLoad_(0),
	requestCount_(0),
	connectionCount_(0),
	thread_(pthread_self()),
	queue_(),
	resumeLock_(),
	resumeCondition_(),
	performanceCounter_(),
	stopHandler_(),
	killHandler_(),
	connections_(nullptr),
	freeConnections_(nullptr),
	evLoopCheck_(loop_),
	evNewConnection_(loop_),
	evWakeup_(loop_),
	fileinfo(loop_, &server_.fileinfoConfig_)
{
	evLoopCheck_.set<HttpWorker, &HttpWorker::onLoopCheck>(this);
	evLoopCheck_.start();

	evNewConnection_.set<HttpWorker, &HttpWorker::onNewConnection>(this);
	evNewConnection_.start();

	evWakeup_.set<&HttpWorker::onWakeup>();
	evWakeup_.start();

	pthread_mutex_init(&resumeLock_, nullptr);
	pthread_cond_init(&resumeCondition_, nullptr);

	if (threaded) {
		pthread_create(&thread_, nullptr, &HttpWorker::_run, this);
	}

	setName("xzero-io/%d", id_);

	TRACE(1, "spawned");
}

HttpWorker::~HttpWorker()
{
	TRACE(1, "destroying");

	clearCustomData();

	pthread_cond_destroy(&resumeCondition_);
	pthread_mutex_destroy(&resumeLock_);

	evLoopCheck_.stop();
	evNewConnection_.stop();
	evWakeup_.stop();

	freeCache();
}

void* HttpWorker::_run(void* p)
{
	reinterpret_cast<HttpWorker*>(p)->run();
	return nullptr;
}

void HttpWorker::run()
{
	state_ = Running;

	// XXX invoke onWorkerSpawned-hook here because we want to ensure this hook is
	// XXX being invoked from *within* the worker-thread.
	server_.onWorkerSpawn(this);

	TRACE(1, "enter loop");
	ev_loop(loop_, 0);

	while (connections_)
		_kill();

	server_.onWorkerUnspawn(this);

	state_ = Inactive;
}

/*!
 * Sets the thread/process name that's running this worker.
 */
void HttpWorker::setName(const char* fmt, ...)
{
	char buf[17]; // the name may be at most 16 bytes long.
	va_list va;

	va_start(va, fmt);
	vsnprintf(buf, sizeof(buf), fmt, va);
	va_end(va);

	pthread_setname_np(thread_, buf);
}

void HttpWorker::log(LogMessage&& msg)
{
	msg.addTag("worker/%u", id());

	server().log(std::forward<LogMessage>(msg));
}

/** enqueues/assigns/registers given client connection information to this worker.
 */
void HttpWorker::enqueue(std::pair<Socket*, ServerSocket*>&& client)
{
	queue_.enqueue(client);
	evNewConnection_.send();
}

/** callback to be invoked when new connection(s) have been assigned to this worker.
 */
void HttpWorker::onNewConnection(ev::async& /*w*/, int /*revents*/)
{
	std::pair<Socket*, ServerSocket*> client;

	while (queue_.dequeue(&client)) {
		spawnConnection(client.first, client.second);
	}
}

void HttpWorker::onWakeup(ev::async& w, int revents)
{
	// no-op - this callback is simply used to wake up the worker's event loop
}

void HttpWorker::spawnConnection(Socket* client, ServerSocket* listener)
{
	TRACE(1, "client connected; fd:%d", client->handle());

	++connectionLoad_;
	++connectionCount_;

	// XXX since socket has not been used so far, I might be able to defer its creation out of its socket descriptor
	// XXX so that I do not have to double-initialize libev's loop handles for this socket.
	client->setLoop(loop_);

	HttpConnection* c;
	if (likely(freeConnections_ != nullptr)) {
		c = freeConnections_;
		c->id_ = connectionCount_;
		freeConnections_ = c->next_;
	}
	else {
		c = new HttpConnection(this, connectionCount_/*id*/);
	}

	if (connections_)
		connections_->prev_ = c;

	c->next_ = connections_;
	connections_ = c;

	c->start(listener, client);
}

/** releases/unregisters given (and to-be-destroyed) connection from this worker.
 *
 * This decrements the connection-load counter by one.
 */
void HttpWorker::release(HttpConnection* c)
{
	//    /--<--\   /--<--\   /--<--\
	// NULL     item1     item2     item3     NULL
	//              \-->--/   \-->--/   \-->--/

	--connectionLoad_;

	// unlink from active-list
	HttpConnection* prev = c->prev_;
	HttpConnection* next = c->next_;

	if (prev)
		prev->next_ = next;

	if (next)
		next->prev_ = prev;

	if (c == connections_)
		connections_ = next;

	// link into free-list
	c->next_ = freeConnections_;
	c->prev_ = nullptr;					// not needed
	if (freeConnections_ && freeConnections_->prev_)
		freeConnections_->prev_ = c;	// not needed
	freeConnections_ = c;
}

/**
 * Clear some cached objects to free up memory.
 */
void HttpWorker::freeCache()
{
	size_t i = 0;
	while (freeConnections_) {
		auto next = freeConnections_->next_;
		delete freeConnections_;
		freeConnections_ = next;
		++i;
	}
	TRACE(1, "cleared %zu free-connections items", i);
}

void HttpWorker::handleRequest(HttpRequest *r)
{
	++requestCount_;
	performanceCounter_.touch(now_.value());

	BufferRef expectHeader = r->requestHeader("Expect");
	bool contentRequired = r->method == "POST" || r->method == "PUT";

	if (contentRequired) {
		if (r->connection.contentLength() == -1 && !r->connection.isChunked()) {
			r->status = HttpStatus::LengthRequired;
			r->finish();
			return;
		}
	} else {
		if (r->contentAvailable()) {
			r->status = HttpStatus::BadRequest; // FIXME do we have a better status code?
			r->finish();
			return;
		}
	}

	if (expectHeader) {
		r->expectingContinue = equals(expectHeader, "100-continue");

		if (!r->expectingContinue || !r->supportsProtocol(1, 1)) {
			r->status = HttpStatus::ExpectationFailed;
			r->finish();
			return;
		}
	}

	server_.onPreProcess(r);

	if (!server_.requestHandler(r))
		r->finish();
}

void HttpWorker::_stop()
{
	TRACE(1, "_stop");

	evLoopCheck_.stop();
	evNewConnection_.stop();
	evWakeup_.stop();

	for (auto handler: stopHandler_)
		handler();
}

void HttpWorker::onLoopCheck(ev::check& /*w*/, int /*revents*/)
{
	// update server time
	now_.update(ev_now(loop_));
}

void HttpWorker::setAffinity(int cpu)
{
	cpu_set_t set;

	CPU_ZERO(&set);
	CPU_SET(cpu, &set);

	TRACE(1, "setAffinity: %d", cpu);

	int rv = pthread_setaffinity_np(thread_, sizeof(set), &set);
	if (rv < 0) {
		log(Severity::error, "setting scheduler affinity on CPU %d failed for worker %u. %s",
			cpu, id_, strerror(errno));
	}
}

void HttpWorker::bind(ServerSocket* s)
{
	s->set<HttpWorker, &HttpWorker::spawnConnection>(this);
}

/** suspend the execution of the worker thread until resume() is invoked.
 *
 * \note has no effect on main worker
 * \see resume()
 */
void HttpWorker::suspend()
{
	TRACE(1, "suspend");

	if (id_ != 0)
		post<HttpWorker, &HttpWorker::_suspend>(this);
}

void HttpWorker::_suspend()
{
	TRACE(1, "_suspend");
	pthread_mutex_lock(&resumeLock_);
	state_ = Suspended;
	pthread_cond_wait(&resumeCondition_, &resumeLock_);
	state_ = Running;
	pthread_mutex_unlock(&resumeLock_);
}

/** resumes the previousely suspended worker thread.
 *
 * \note has no effect on main worker
 * \see suspend()
 */
void HttpWorker::resume()
{
	TRACE(1, "resume");
	if (id_ != 0)
		pthread_cond_signal(&resumeCondition_);
}

void HttpWorker::stop()
{
	TRACE(1, "stop: post -> _stop() (while in state: %d)", state_);

	if (state_ != Running)
		return;

//	fileinfo.stop();

	post<HttpWorker, &HttpWorker::_stop>(this);
}

void HttpWorker::join()
{
	if (thread_ != pthread_self()) {
		pthread_join(thread_, nullptr);
	}
}

/*! Actually aborts all active connections.
 *
 * \see HttpConnection::abort()
 */
void HttpWorker::kill()
{
	TRACE(1, "kill: post -> _kill()");
	post<HttpWorker, &HttpWorker::_kill>(this);
}

/*! Actually aborts all active connections.
 *
 * \note Must be invoked from within the worker's thread.
 *
 * \see HttpConnection::abort()
 */
void HttpWorker::_kill()
{
	TRACE(1, "_kill()");
	while (connections_) {
		std::list<HttpConnection*> copy;

		for (HttpConnection* c = connections_; c != nullptr; c = c->next_)
			copy.push_back(c);

		for (auto c: copy)
			c->abort();

#ifndef XZERO_NDEBUG
		for (HttpConnection* c = connections_; c != nullptr; c = c->next_)
			c->log(Severity::debug, "connection still open");
#endif
	}

	for (auto handler: killHandler_) {
		TRACE(1, "_kill: invoke kill handler");
		handler();
	}
}

std::list<std::function<void()>>::iterator HttpWorker::registerStopHandler(std::function<void()> callback)
{
	stopHandler_.push_front(callback);
	return stopHandler_.begin();
}

void HttpWorker::unregisterStopHandler(std::list<std::function<void()>>::iterator handle)
{
	stopHandler_.erase(handle);
}

std::list<std::function<void()>>::iterator HttpWorker::registerKillHandler(std::function<void()> callback)
{
	killHandler_.push_front(callback);
	return killHandler_.begin();
}

void HttpWorker::unregisterKillHandler(std::list<std::function<void()>>::iterator handle)
{
	killHandler_.erase(handle);
}

void HttpWorker::post_thunk3(int revents, void* arg)
{
	std::function<void()>* callback = static_cast<std::function<void()>*>(arg);
	(*callback)();
	delete callback;
}

} // namespace x0
<commit_msg>no pthread_setname_np on osx<commit_after>/* <src/HttpWorker.cpp>
 *
 * This file is part of the x0 web server project and is released under GPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2013 Christian Parpart <trapni@gmail.com>
 */

#include <x0/http/HttpWorker.h>
#include <x0/http/HttpRequest.h>
#include <x0/http/HttpServer.h>
#include <x0/http/HttpConnection.h>
#include <x0/ServerSocket.h>
#include <x0/DebugLogger.h>

#include <algorithm>
#include <cstdarg>
#include <ev++.h>
#include <signal.h>
#include <pthread.h>

// XXX one a connection has been passed to a worker, it is *bound* to it.

#if 0//!defined(XZERO_NDEBUG)
//#	define TRACE(n, msg...) X0_DEBUG("worker", (n), msg)
#	define TRACE(n, msg...) log(Severity::debug ## n, msg)
#else
#	define TRACE(n, msg...) do {} while (0)
#endif

namespace x0 {

/*!
 * Creates an HTTP worker instance.
 *
 * \param server   the worker parents server instance
 * \param loop     the event loop to be used within this worker
 * \param id       unique ID within the server instance
 * \param threaded whether or not to spawn a thread to actually run this worker
 */
HttpWorker::HttpWorker(HttpServer& server, struct ev_loop *loop, unsigned int id, bool threaded) :
	id_(id),
	state_(Inactive),
	server_(server),
	loop_(loop),
	startupTime_(ev_now(loop_)),
	now_(),
	connectionLoad_(0),
	requestCount_(0),
	connectionCount_(0),
	thread_(pthread_self()),
	queue_(),
	resumeLock_(),
	resumeCondition_(),
	performanceCounter_(),
	stopHandler_(),
	killHandler_(),
	connections_(nullptr),
	freeConnections_(nullptr),
	evLoopCheck_(loop_),
	evNewConnection_(loop_),
	evWakeup_(loop_),
	fileinfo(loop_, &server_.fileinfoConfig_)
{
	evLoopCheck_.set<HttpWorker, &HttpWorker::onLoopCheck>(this);
	evLoopCheck_.start();

	evNewConnection_.set<HttpWorker, &HttpWorker::onNewConnection>(this);
	evNewConnection_.start();

	evWakeup_.set<&HttpWorker::onWakeup>();
	evWakeup_.start();

	pthread_mutex_init(&resumeLock_, nullptr);
	pthread_cond_init(&resumeCondition_, nullptr);

	if (threaded) {
		pthread_create(&thread_, nullptr, &HttpWorker::_run, this);
	}

	setName("xzero-io/%d", id_);

	TRACE(1, "spawned");
}

HttpWorker::~HttpWorker()
{
	TRACE(1, "destroying");

	clearCustomData();

	pthread_cond_destroy(&resumeCondition_);
	pthread_mutex_destroy(&resumeLock_);

	evLoopCheck_.stop();
	evNewConnection_.stop();
	evWakeup_.stop();

	freeCache();
}

void* HttpWorker::_run(void* p)
{
	reinterpret_cast<HttpWorker*>(p)->run();
	return nullptr;
}

void HttpWorker::run()
{
	state_ = Running;

	// XXX invoke onWorkerSpawned-hook here because we want to ensure this hook is
	// XXX being invoked from *within* the worker-thread.
	server_.onWorkerSpawn(this);

	TRACE(1, "enter loop");
	ev_loop(loop_, 0);

	while (connections_)
		_kill();

	server_.onWorkerUnspawn(this);

	state_ = Inactive;
}

/*!
 * Sets the thread/process name that's running this worker.
 */
void HttpWorker::setName(const char* fmt, ...)
{
	char buf[17]; // the name may be at most 16 bytes long.
	va_list va;

	va_start(va, fmt);
	vsnprintf(buf, sizeof(buf), fmt, va);
	va_end(va);

#ifndef __APPLE__
	pthread_setname_np(thread_, buf);
#endif
}

void HttpWorker::log(LogMessage&& msg)
{
	msg.addTag("worker/%u", id());

	server().log(std::forward<LogMessage>(msg));
}

/** enqueues/assigns/registers given client connection information to this worker.
 */
void HttpWorker::enqueue(std::pair<Socket*, ServerSocket*>&& client)
{
	queue_.enqueue(client);
	evNewConnection_.send();
}

/** callback to be invoked when new connection(s) have been assigned to this worker.
 */
void HttpWorker::onNewConnection(ev::async& /*w*/, int /*revents*/)
{
	std::pair<Socket*, ServerSocket*> client;

	while (queue_.dequeue(&client)) {
		spawnConnection(client.first, client.second);
	}
}

void HttpWorker::onWakeup(ev::async& w, int revents)
{
	// no-op - this callback is simply used to wake up the worker's event loop
}

void HttpWorker::spawnConnection(Socket* client, ServerSocket* listener)
{
	TRACE(1, "client connected; fd:%d", client->handle());

	++connectionLoad_;
	++connectionCount_;

	// XXX since socket has not been used so far, I might be able to defer its creation out of its socket descriptor
	// XXX so that I do not have to double-initialize libev's loop handles for this socket.
	client->setLoop(loop_);

	HttpConnection* c;
	if (likely(freeConnections_ != nullptr)) {
		c = freeConnections_;
		c->id_ = connectionCount_;
		freeConnections_ = c->next_;
	}
	else {
		c = new HttpConnection(this, connectionCount_/*id*/);
	}

	if (connections_)
		connections_->prev_ = c;

	c->next_ = connections_;
	connections_ = c;

	c->start(listener, client);
}

/** releases/unregisters given (and to-be-destroyed) connection from this worker.
 *
 * This decrements the connection-load counter by one.
 */
void HttpWorker::release(HttpConnection* c)
{
	//    /--<--\   /--<--\   /--<--\
	// NULL     item1     item2     item3     NULL
	//              \-->--/   \-->--/   \-->--/

	--connectionLoad_;

	// unlink from active-list
	HttpConnection* prev = c->prev_;
	HttpConnection* next = c->next_;

	if (prev)
		prev->next_ = next;

	if (next)
		next->prev_ = prev;

	if (c == connections_)
		connections_ = next;

	// link into free-list
	c->next_ = freeConnections_;
	c->prev_ = nullptr;					// not needed
	if (freeConnections_ && freeConnections_->prev_)
		freeConnections_->prev_ = c;	// not needed
	freeConnections_ = c;
}

/**
 * Clear some cached objects to free up memory.
 */
void HttpWorker::freeCache()
{
	size_t i = 0;
	while (freeConnections_) {
		auto next = freeConnections_->next_;
		delete freeConnections_;
		freeConnections_ = next;
		++i;
	}
	TRACE(1, "cleared %zu free-connections items", i);
}

void HttpWorker::handleRequest(HttpRequest *r)
{
	++requestCount_;
	performanceCounter_.touch(now_.value());

	BufferRef expectHeader = r->requestHeader("Expect");
	bool contentRequired = r->method == "POST" || r->method == "PUT";

	if (contentRequired) {
		if (r->connection.contentLength() == -1 && !r->connection.isChunked()) {
			r->status = HttpStatus::LengthRequired;
			r->finish();
			return;
		}
	} else {
		if (r->contentAvailable()) {
			r->status = HttpStatus::BadRequest; // FIXME do we have a better status code?
			r->finish();
			return;
		}
	}

	if (expectHeader) {
		r->expectingContinue = equals(expectHeader, "100-continue");

		if (!r->expectingContinue || !r->supportsProtocol(1, 1)) {
			r->status = HttpStatus::ExpectationFailed;
			r->finish();
			return;
		}
	}

	server_.onPreProcess(r);

	if (!server_.requestHandler(r))
		r->finish();
}

void HttpWorker::_stop()
{
	TRACE(1, "_stop");

	evLoopCheck_.stop();
	evNewConnection_.stop();
	evWakeup_.stop();

	for (auto handler: stopHandler_)
		handler();
}

void HttpWorker::onLoopCheck(ev::check& /*w*/, int /*revents*/)
{
	// update server time
	now_.update(ev_now(loop_));
}

void HttpWorker::setAffinity(int cpu)
{
	cpu_set_t set;

	CPU_ZERO(&set);
	CPU_SET(cpu, &set);

	TRACE(1, "setAffinity: %d", cpu);

	int rv = pthread_setaffinity_np(thread_, sizeof(set), &set);
	if (rv < 0) {
		log(Severity::error, "setting scheduler affinity on CPU %d failed for worker %u. %s",
			cpu, id_, strerror(errno));
	}
}

void HttpWorker::bind(ServerSocket* s)
{
	s->set<HttpWorker, &HttpWorker::spawnConnection>(this);
}

/** suspend the execution of the worker thread until resume() is invoked.
 *
 * \note has no effect on main worker
 * \see resume()
 */
void HttpWorker::suspend()
{
	TRACE(1, "suspend");

	if (id_ != 0)
		post<HttpWorker, &HttpWorker::_suspend>(this);
}

void HttpWorker::_suspend()
{
	TRACE(1, "_suspend");
	pthread_mutex_lock(&resumeLock_);
	state_ = Suspended;
	pthread_cond_wait(&resumeCondition_, &resumeLock_);
	state_ = Running;
	pthread_mutex_unlock(&resumeLock_);
}

/** resumes the previousely suspended worker thread.
 *
 * \note has no effect on main worker
 * \see suspend()
 */
void HttpWorker::resume()
{
	TRACE(1, "resume");
	if (id_ != 0)
		pthread_cond_signal(&resumeCondition_);
}

void HttpWorker::stop()
{
	TRACE(1, "stop: post -> _stop() (while in state: %d)", state_);

	if (state_ != Running)
		return;

//	fileinfo.stop();

	post<HttpWorker, &HttpWorker::_stop>(this);
}

void HttpWorker::join()
{
	if (thread_ != pthread_self()) {
		pthread_join(thread_, nullptr);
	}
}

/*! Actually aborts all active connections.
 *
 * \see HttpConnection::abort()
 */
void HttpWorker::kill()
{
	TRACE(1, "kill: post -> _kill()");
	post<HttpWorker, &HttpWorker::_kill>(this);
}

/*! Actually aborts all active connections.
 *
 * \note Must be invoked from within the worker's thread.
 *
 * \see HttpConnection::abort()
 */
void HttpWorker::_kill()
{
	TRACE(1, "_kill()");
	while (connections_) {
		std::list<HttpConnection*> copy;

		for (HttpConnection* c = connections_; c != nullptr; c = c->next_)
			copy.push_back(c);

		for (auto c: copy)
			c->abort();

#ifndef XZERO_NDEBUG
		for (HttpConnection* c = connections_; c != nullptr; c = c->next_)
			c->log(Severity::debug, "connection still open");
#endif
	}

	for (auto handler: killHandler_) {
		TRACE(1, "_kill: invoke kill handler");
		handler();
	}
}

std::list<std::function<void()>>::iterator HttpWorker::registerStopHandler(std::function<void()> callback)
{
	stopHandler_.push_front(callback);
	return stopHandler_.begin();
}

void HttpWorker::unregisterStopHandler(std::list<std::function<void()>>::iterator handle)
{
	stopHandler_.erase(handle);
}

std::list<std::function<void()>>::iterator HttpWorker::registerKillHandler(std::function<void()> callback)
{
	killHandler_.push_front(callback);
	return killHandler_.begin();
}

void HttpWorker::unregisterKillHandler(std::list<std::function<void()>>::iterator handle)
{
	killHandler_.erase(handle);
}

void HttpWorker::post_thunk3(int revents, void* arg)
{
	std::function<void()>* callback = static_cast<std::function<void()>*>(arg);
	(*callback)();
	delete callback;
}

} // namespace x0
<|endoftext|>


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

#include "config/use_checker.hh"

#include "arch/mips/faults.hh"
#include "base/cprintf.hh"
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "cpu/checker/thread_context.hh"
#include "sim/sim_events.hh"
#include "sim/stats.hh"

#include "cpu/o3/mips/cpu.hh"
#include "cpu/o3/mips/params.hh"
#include "cpu/o3/mips/thread_context.hh"
#include "cpu/o3/comm.hh"
#include "cpu/o3/thread_state.hh"

template <class Impl>
MipsO3CPU<Impl>::MipsO3CPU(Params *params)
    : FullO3CPU<Impl>(params)
{
    DPRINTF(O3CPU, "Creating MipsO3CPU object.\n");

    // Setup any thread state.
    this->thread.resize(this->numThreads);

    for (int i = 0; i < this->numThreads; ++i) {
        if (i < params->workload.size()) {
            DPRINTF(O3CPU, "Workload[%i] process is %#x",
                    i, this->thread[i]);
            this->thread[i] = new Thread(this, i, params->workload[i], i);

            this->thread[i]->setStatus(ThreadContext::Suspended);

            //usedTids[i] = true;
            //threadMap[i] = i;
        } else {
            //Allocate Empty thread so M5 can use later
            //when scheduling threads to CPU
            Process* dummy_proc = NULL;

            this->thread[i] = new Thread(this, i, dummy_proc, i);
            //usedTids[i] = false;
        }

        ThreadContext *tc;

        // Setup the TC that will serve as the interface to the threads/CPU.
        MipsTC<Impl> *mips_tc =
            new MipsTC<Impl>;

        tc = mips_tc;

        // If we're using a checker, then the TC should be the
        // CheckerThreadContext.
#if USE_CHECKER
        if (params->checker) {
            tc = new CheckerThreadContext<MipsTC<Impl> >(
                mips_tc, this->checker);
        }
#endif

        mips_tc->cpu = this;
        mips_tc->thread = this->thread[i];

        // Give the thread the TC.
        this->thread[i]->tc = tc;

        // Add the TC to the CPU's list of TC's.
        this->threadContexts.push_back(tc);
    }

    for (int i=0; i < this->numThreads; i++) {
        this->thread[i]->setFuncExeInst(0);
    }

    // Sets CPU pointers. These must be set at this level because the CPU
    // pointers are defined to be the highest level of CPU class.
    this->fetch.setCPU(this);
    this->decode.setCPU(this);
    this->rename.setCPU(this);
    this->iew.setCPU(this);
    this->commit.setCPU(this);

    this->rob.setCPU(this);
    this->regFile.setCPU(this);

    lockAddr = 0;
    lockFlag = false;
}

template <class Impl>
void
MipsO3CPU<Impl>::regStats()
{
    // Register stats for everything that has stats.
    this->fullCPURegStats();
    this->fetch.regStats();
    this->decode.regStats();
    this->rename.regStats();
    this->iew.regStats();
    this->commit.regStats();
}

template <class Impl>
MiscReg
MipsO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
{
    return this->regFile.readMiscReg(misc_reg, tid);
}

template <class Impl>
MiscReg
MipsO3CPU<Impl>::readMiscRegWithEffect(int misc_reg, unsigned tid)
{
    return this->regFile.readMiscRegWithEffect(misc_reg, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid)
{
    this->regFile.setMiscReg(misc_reg, val, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val,
                                       unsigned tid)
{
    this->regFile.setMiscRegWithEffect(misc_reg, val, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::squashFromTC(unsigned tid)
{
    this->thread[tid]->inSyscall = true;
    this->commit.generateTCEvent(tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::trap(Fault fault, unsigned tid)
{
    // Pass the thread's TC into the invoke method.
    fault->invoke(this->threadContexts[tid]);
}

#if !FULL_SYSTEM

template <class Impl>
void
MipsO3CPU<Impl>::syscall(int64_t callnum, int tid)
{
    DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid);

    DPRINTF(Activity,"Activity: syscall() called.\n");

    // Temporarily increase this by one to account for the syscall
    // instruction.
    ++(this->thread[tid]->funcExeInst);

    // Execute the actual syscall.
    this->thread[tid]->syscall(callnum);

    // Decrease funcExeInst by one as the normal commit will handle
    // incrementing it.
    --(this->thread[tid]->funcExeInst);

    DPRINTF(O3CPU, "[tid:%i] Register 2 is %i ", tid, this->readIntReg(2));
}

template <class Impl>
TheISA::IntReg
MipsO3CPU<Impl>::getSyscallArg(int i, int tid)
{
    return this->readArchIntReg(MipsISA::ArgumentReg0 + i, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid)
{
    this->setArchIntReg(MipsISA::ArgumentReg0 + i, val, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
{
    // check for error condition.
    if (return_value.successful()) {
        // no error
        this->setArchIntReg(TheISA::SyscallSuccessReg, 0, tid);
        this->setArchIntReg(TheISA::ReturnValueReg, return_value.value(), tid);
    } else {
        // got an error, return details
        this->setArchIntReg(TheISA::SyscallSuccessReg,
                (TheISA::IntReg) -1, tid);
        this->setArchIntReg(TheISA::ReturnValueReg, -return_value.value(), tid);
    }
}
#endif
<commit_msg>Use the setSyscallReturn defined in arch rather than duplicating it here.<commit_after>/*
 * Copyright (c) 2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Kevin Lim
 *          Korey Sewell
 */

#include "config/use_checker.hh"

#include "arch/mips/faults.hh"
#include "base/cprintf.hh"
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "cpu/checker/thread_context.hh"
#include "sim/sim_events.hh"
#include "sim/stats.hh"

#include "cpu/o3/mips/cpu.hh"
#include "cpu/o3/mips/params.hh"
#include "cpu/o3/mips/thread_context.hh"
#include "cpu/o3/comm.hh"
#include "cpu/o3/thread_state.hh"

template <class Impl>
MipsO3CPU<Impl>::MipsO3CPU(Params *params)
    : FullO3CPU<Impl>(params)
{
    DPRINTF(O3CPU, "Creating MipsO3CPU object.\n");

    // Setup any thread state.
    this->thread.resize(this->numThreads);

    for (int i = 0; i < this->numThreads; ++i) {
        if (i < params->workload.size()) {
            DPRINTF(O3CPU, "Workload[%i] process is %#x",
                    i, this->thread[i]);
            this->thread[i] = new Thread(this, i, params->workload[i], i);

            this->thread[i]->setStatus(ThreadContext::Suspended);

            //usedTids[i] = true;
            //threadMap[i] = i;
        } else {
            //Allocate Empty thread so M5 can use later
            //when scheduling threads to CPU
            Process* dummy_proc = NULL;

            this->thread[i] = new Thread(this, i, dummy_proc, i);
            //usedTids[i] = false;
        }

        ThreadContext *tc;

        // Setup the TC that will serve as the interface to the threads/CPU.
        MipsTC<Impl> *mips_tc =
            new MipsTC<Impl>;

        tc = mips_tc;

        // If we're using a checker, then the TC should be the
        // CheckerThreadContext.
#if USE_CHECKER
        if (params->checker) {
            tc = new CheckerThreadContext<MipsTC<Impl> >(
                mips_tc, this->checker);
        }
#endif

        mips_tc->cpu = this;
        mips_tc->thread = this->thread[i];

        // Give the thread the TC.
        this->thread[i]->tc = tc;

        // Add the TC to the CPU's list of TC's.
        this->threadContexts.push_back(tc);
    }

    for (int i=0; i < this->numThreads; i++) {
        this->thread[i]->setFuncExeInst(0);
    }

    // Sets CPU pointers. These must be set at this level because the CPU
    // pointers are defined to be the highest level of CPU class.
    this->fetch.setCPU(this);
    this->decode.setCPU(this);
    this->rename.setCPU(this);
    this->iew.setCPU(this);
    this->commit.setCPU(this);

    this->rob.setCPU(this);
    this->regFile.setCPU(this);

    lockAddr = 0;
    lockFlag = false;
}

template <class Impl>
void
MipsO3CPU<Impl>::regStats()
{
    // Register stats for everything that has stats.
    this->fullCPURegStats();
    this->fetch.regStats();
    this->decode.regStats();
    this->rename.regStats();
    this->iew.regStats();
    this->commit.regStats();
}

template <class Impl>
MiscReg
MipsO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
{
    return this->regFile.readMiscReg(misc_reg, tid);
}

template <class Impl>
MiscReg
MipsO3CPU<Impl>::readMiscRegWithEffect(int misc_reg, unsigned tid)
{
    return this->regFile.readMiscRegWithEffect(misc_reg, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid)
{
    this->regFile.setMiscReg(misc_reg, val, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val,
                                       unsigned tid)
{
    this->regFile.setMiscRegWithEffect(misc_reg, val, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::squashFromTC(unsigned tid)
{
    this->thread[tid]->inSyscall = true;
    this->commit.generateTCEvent(tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::trap(Fault fault, unsigned tid)
{
    // Pass the thread's TC into the invoke method.
    fault->invoke(this->threadContexts[tid]);
}

#if !FULL_SYSTEM

template <class Impl>
void
MipsO3CPU<Impl>::syscall(int64_t callnum, int tid)
{
    DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid);

    DPRINTF(Activity,"Activity: syscall() called.\n");

    // Temporarily increase this by one to account for the syscall
    // instruction.
    ++(this->thread[tid]->funcExeInst);

    // Execute the actual syscall.
    this->thread[tid]->syscall(callnum);

    // Decrease funcExeInst by one as the normal commit will handle
    // incrementing it.
    --(this->thread[tid]->funcExeInst);

    DPRINTF(O3CPU, "[tid:%i] Register 2 is %i ", tid, this->readIntReg(2));
}

template <class Impl>
TheISA::IntReg
MipsO3CPU<Impl>::getSyscallArg(int i, int tid)
{
    return this->readArchIntReg(MipsISA::ArgumentReg0 + i, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid)
{
    this->setArchIntReg(MipsISA::ArgumentReg0 + i, val, tid);
}

template <class Impl>
void
MipsO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
{
    TheISA::setSyscallReturn(return_value, this->tcBase(tid));
}
#endif
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu
// This code accompanies the book:
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
//     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author or Addison-Wesley Longman make no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

// Last update: June 20, 2001

#include "Singleton.h"

using namespace Loki::Private;

Loki::Private::TrackerArray Loki::Private::pTrackerArray = 0;
unsigned int Loki::Private::elements = 0;

////////////////////////////////////////////////////////////////////////////////
// function AtExitFn
// Ensures proper destruction of objects with longevity
////////////////////////////////////////////////////////////////////////////////

void Loki::Private::AtExitFn()
{
    assert(elements > 0 && pTrackerArray != 0);
    // Pick the element at the top of the stack
    LifetimeTracker* pTop = pTrackerArray[elements - 1];
    // Remove that object off the stack
    // Don't check errors - realloc with less memory
    //     can't fail
    pTrackerArray = static_cast<TrackerArray>(std::realloc(
        pTrackerArray, sizeof(T) * --elements));
    // Destroy the element
    delete pTop;
}

////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// January 10, 2002: Fixed bug in call to realloc - credit due to Nigel Gent and
//      Eike Petersen
////////////////////////////////////////////////////////////////////////////////
<commit_msg>Refixed bug in call to realloc<commit_after>////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Copyright (c) 2001 by Andrei Alexandrescu
// This code accompanies the book:
// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
//     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
// Permission to use, copy, modify, distribute and sell this software for any
//     purpose is hereby granted without fee, provided that the above copyright
//     notice appear in all copies and that both that copyright notice and this
//     permission notice appear in supporting documentation.
// The author or Addison-Wesley Longman make no representations about the
//     suitability of this software for any purpose. It is provided "as is"
//     without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////

// Last update: June 20, 2001

#include "Singleton.h"

using namespace Loki::Private;

Loki::Private::TrackerArray Loki::Private::pTrackerArray = 0;
unsigned int Loki::Private::elements = 0;

////////////////////////////////////////////////////////////////////////////////
// function AtExitFn
// Ensures proper destruction of objects with longevity
////////////////////////////////////////////////////////////////////////////////

void Loki::Private::AtExitFn()
{
    assert(elements > 0 && pTrackerArray != 0);
    // Pick the element at the top of the stack
    LifetimeTracker* pTop = pTrackerArray[elements - 1];
    // Remove that object off the stack
    // Don't check errors - realloc with less memory
    //     can't fail
    pTrackerArray = static_cast<TrackerArray>(std::realloc(
        pTrackerArray, sizeof(*pTrackerArray) * --elements));
    // Destroy the element
    delete pTop;
}

////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// January 10, 2002: Fixed bug in call to realloc - credit due to Nigel Gent and
//      Eike Petersen
// May 08, 2002: Refixed bug in call to realloc
////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


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

#ifdef HAVE_LIBXML2

// mapnik
#include <mapnik/xml_loader.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/util/trim.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/util/fs.hpp>

// libxml
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/parserInternals.h>
#include <libxml/xinclude.h>

// libxslt
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include <libexslt/exslt.h>

// stl
#include <stdexcept>
#include <iostream>

#define DEFAULT_OPTIONS (XML_PARSE_NOWARNING | XML_PARSE_NOENT | XML_PARSE_NOBLANKS | XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA)

#define isnbsp(s)       ((s)[0] == '\xC2' && (s)[1] == '\xA0')

namespace mapnik
{
class libxml2_loader : util::noncopyable
{
public:
    libxml2_loader(const char *encoding = nullptr, int options = DEFAULT_OPTIONS, const char *url = nullptr) :
        ctx_(0),
        encoding_(encoding),
        options_(options),
        url_(url)
    {
        LIBXML_TEST_VERSION;
        ctx_ = xmlNewParserCtxt();
        if (!ctx_)
        {
            throw std::runtime_error("Failed to create parser context.");
        }
        exsltRegisterAll();
    }

    ~libxml2_loader()
    {
        if (ctx_)
        {
            xmlFreeParserCtxt(ctx_);
        }
    }

    void load(std::string const& filename, xml_node &node)
    {
        if (!mapnik::util::exists(filename))
        {
            throw config_error(std::string("Could not load map file: File does not exist"), 0, filename);
        }

        xmlDocPtr doc = xmlCtxtReadFile(ctx_, filename.c_str(), encoding_, options_);

        if (!doc)
        {
            xmlError * error = xmlCtxtGetLastError(ctx_);
            if (error)
            {
                std::string msg("XML document not well formed:\n");
                msg += error->message;
                // remove CR
                msg = msg.substr(0, msg.size() - 1);
                throw config_error(msg, error->line, error->file);
            }
        }

        xmlDocPtr res = preprocess(doc);

        if (res)
        {
            xmlFreeDoc(doc);
            doc = res;
        }

        load(doc, node);
    }

    void load(const int fd, xml_node &node)
    {
        xmlDocPtr doc = xmlCtxtReadFd(ctx_, fd, url_, encoding_, options_);

        xmlDocPtr res = preprocess(doc);

        if (res)
        {
            xmlFreeDoc(doc);
            doc = res;
        }

        load(doc, node);
    }

    void load_string(std::string const& buffer, xml_node &node, std::string const & base_path)
    {
        if (!base_path.empty())
        {
            if (!mapnik::util::exists(base_path)) {
                throw config_error(std::string("Could not locate base_path '") +
                                   base_path + "': file or directory does not exist");
            }
        }
        // NOTE: base_path here helps libxml2 resolve entities correctly: https://github.com/mapnik/mapnik/issues/440
        xmlDocPtr doc = xmlCtxtReadMemory(ctx_, buffer.data(), buffer.length(), base_path.c_str(), encoding_, options_);

        xmlDocPtr res = preprocess(doc);

        if (res)
        {
            xmlFreeDoc(doc);
            doc = res;
        }

        load(doc, node);
    }

    xmlDocPtr preprocess(xmlDocPtr doc)
    {
        xsltStylesheetPtr style = xsltLoadStylesheetPI(doc);

        if (style)
        {
            xsltTransformContextPtr transform_ctx = xsltNewTransformContext(style, doc);

            if (transform_ctx)
            {
                xsltSetCtxtParseOptions(transform_ctx, options_);
                xmlDocPtr res = xsltApplyStylesheetUser(style, doc, NULL, NULL, NULL, transform_ctx);
                xsltFreeTransformContext(transform_ctx);
                xsltFreeStylesheet(style);
                return res;
            }

            xsltFreeStylesheet(style);
        }
        return NULL;
    }

    void load(const xmlDocPtr doc, xml_node &node)
    {
        if (!doc)
        {
            std::string msg("XML document not well formed");
            xmlError * error = xmlCtxtGetLastError( ctx_ );
            if (error)
            {
                msg += ":\n";
                msg += error->message;
                throw config_error(msg, error->line, error->file);
            }
            else
            {
                throw config_error(msg);
            }
        }

        int iXIncludeReturn = xmlXIncludeProcessFlags(doc, options_);

        if (iXIncludeReturn < 0)
        {
            xmlFreeDoc(doc);
            throw config_error("XML XInclude error.  One or more files failed to load.");
        }

        xmlNode * root = xmlDocGetRootElement(doc);
        if (!root) {
            xmlFreeDoc(doc);
            throw config_error("XML document is empty.");
        }

        populate_tree(root, node);
        xmlFreeDoc(doc);
    }

private:
    void inline append_attributes(xmlAttr *attributes, xml_node & node)
    {
        for (; attributes; attributes = attributes->next )
        {
            node.add_attribute(reinterpret_cast<const char *>(attributes->name),
                               reinterpret_cast<const char *>(attributes->children->content));
        }
    }

    void inline populate_tree(xmlNode *cur_node, xml_node &node)
    {
        for (; cur_node; cur_node = cur_node->next )
        {
            switch (cur_node->type)
            {
            case XML_ELEMENT_NODE:
            {
                xml_node &new_node = node.add_child(reinterpret_cast<const char *>(cur_node->name), cur_node->line, false);
                append_attributes(cur_node->properties, new_node);
                populate_tree(cur_node->children, new_node);
            }
            break;
            case XML_TEXT_NODE:
            {
                std::string trimmed(reinterpret_cast<const char *>(cur_node->content));
                mapnik::util::trim(trimmed);
                if (trimmed.empty()) break; //Don't add empty text nodes
                node.add_child(trimmed.c_str(), cur_node->line, true);
            }
            break;
            case XML_COMMENT_NODE:
                break;
            default:
                break;

            }
        }
    }

    xmlParserCtxtPtr ctx_;
    const char *encoding_;
    int options_;
    const char *url_;
};

void read_xml(std::string const & filename, xml_node &node)
{
    libxml2_loader loader;
    loader.load(filename, node);
}
void read_xml_string(std::string const & str, xml_node &node, std::string const & base_path)
{
    libxml2_loader loader;
    loader.load_string(str, node, base_path);
}

} // end of namespace mapnik

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

#ifdef HAVE_LIBXML2

// mapnik
#include <mapnik/xml_loader.hpp>
#include <mapnik/xml_node.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/util/trim.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/util/fs.hpp>

// libxml
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/parserInternals.h>
#include <libxml/xinclude.h>

// libxslt
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include <libexslt/exslt.h>

// stl
#include <stdexcept>
#include <iostream>

#define DEFAULT_OPTIONS (XML_PARSE_NOENT | XML_PARSE_NOBLANKS | XML_PARSE_DTDLOAD | XML_PARSE_NOCDATA)

#define isnbsp(s)       ((s)[0] == '\xC2' && (s)[1] == '\xA0')

namespace mapnik
{
class libxml2_loader : util::noncopyable
{
public:
    libxml2_loader(const char *encoding = nullptr, int options = DEFAULT_OPTIONS, const char *url = nullptr) :
        ctx_(0),
        encoding_(encoding),
        options_(options),
        url_(url)
    {
        LIBXML_TEST_VERSION;
        ctx_ = xmlNewParserCtxt();
        if (!ctx_)
        {
            throw std::runtime_error("Failed to create parser context.");
        }
        exsltRegisterAll();
    }

    ~libxml2_loader()
    {
        if (ctx_)
        {
            xmlFreeParserCtxt(ctx_);
        }
    }

    void load(std::string const& filename, xml_node &node)
    {
        if (!mapnik::util::exists(filename))
        {
            throw config_error(std::string("Could not load map file: File does not exist"), 0, filename);
        }

        xmlDocPtr doc = xmlCtxtReadFile(ctx_, filename.c_str(), encoding_, options_);

        if (!doc)
        {
            xmlError * error = xmlCtxtGetLastError(ctx_);
            if (error)
            {
                std::string msg("XML document not well formed:\n");
                msg += error->message;
                // remove CR
                msg = msg.substr(0, msg.size() - 1);
                throw config_error(msg, error->line, error->file);
            }
        }

        xmlDocPtr res = preprocess(doc);

        if (res)
        {
            xmlFreeDoc(doc);
            doc = res;
        }

        load(doc, node);
    }

    void load(const int fd, xml_node &node)
    {
        xmlDocPtr doc = xmlCtxtReadFd(ctx_, fd, url_, encoding_, options_);

        xmlDocPtr res = preprocess(doc);

        if (res)
        {
            xmlFreeDoc(doc);
            doc = res;
        }

        load(doc, node);
    }

    void load_string(std::string const& buffer, xml_node &node, std::string const & base_path)
    {
        if (!base_path.empty())
        {
            if (!mapnik::util::exists(base_path)) {
                throw config_error(std::string("Could not locate base_path '") +
                                   base_path + "': file or directory does not exist");
            }
        }
        // NOTE: base_path here helps libxml2 resolve entities correctly: https://github.com/mapnik/mapnik/issues/440
        xmlDocPtr doc = xmlCtxtReadMemory(ctx_, buffer.data(), buffer.length(), base_path.c_str(), encoding_, options_);

        xmlDocPtr res = preprocess(doc);

        if (res)
        {
            xmlFreeDoc(doc);
            doc = res;
        }

        load(doc, node);
    }

    xmlDocPtr preprocess(xmlDocPtr doc)
    {
        xsltStylesheetPtr style = xsltLoadStylesheetPI(doc);

        if (style)
        {
            xsltTransformContextPtr transform_ctx = xsltNewTransformContext(style, doc);

            if (transform_ctx)
            {
                xsltSetCtxtParseOptions(transform_ctx, options_);
                xmlDocPtr res = xsltApplyStylesheetUser(style, doc, NULL, NULL, NULL, transform_ctx);
                xsltFreeTransformContext(transform_ctx);
                xsltFreeStylesheet(style);
                return res;
            }

            xsltFreeStylesheet(style);
        }
        return NULL;
    }

    void load(const xmlDocPtr doc, xml_node &node)
    {
        if (!doc)
        {
            std::string msg("XML document not well formed");
            xmlError * error = xmlCtxtGetLastError( ctx_ );
            if (error)
            {
                msg += ":\n";
                msg += error->message;
                throw config_error(msg, error->line, error->file);
            }
            else
            {
                throw config_error(msg);
            }
        }

        int iXIncludeReturn = xmlXIncludeProcessFlags(doc, options_);

        if (iXIncludeReturn < 0)
        {
            xmlFreeDoc(doc);
            throw config_error("XML XInclude error.  One or more files failed to load.");
        }

        xmlNode * root = xmlDocGetRootElement(doc);
        if (!root) {
            xmlFreeDoc(doc);
            throw config_error("XML document is empty.");
        }

        populate_tree(root, node);
        xmlFreeDoc(doc);
    }

private:
    void inline append_attributes(xmlAttr *attributes, xml_node & node)
    {
        for (; attributes; attributes = attributes->next )
        {
            node.add_attribute(reinterpret_cast<const char *>(attributes->name),
                               reinterpret_cast<const char *>(attributes->children->content));
        }
    }

    void inline populate_tree(xmlNode *cur_node, xml_node &node)
    {
        for (; cur_node; cur_node = cur_node->next )
        {
            switch (cur_node->type)
            {
            case XML_ELEMENT_NODE:
            {
                xml_node &new_node = node.add_child(reinterpret_cast<const char *>(cur_node->name), cur_node->line, false);
                append_attributes(cur_node->properties, new_node);
                populate_tree(cur_node->children, new_node);
            }
            break;
            case XML_TEXT_NODE:
            {
                std::string trimmed(reinterpret_cast<const char *>(cur_node->content));
                mapnik::util::trim(trimmed);
                if (trimmed.empty()) break; //Don't add empty text nodes
                node.add_child(trimmed.c_str(), cur_node->line, true);
            }
            break;
            case XML_COMMENT_NODE:
                break;
            default:
                break;

            }
        }
    }

    xmlParserCtxtPtr ctx_;
    const char *encoding_;
    int options_;
    const char *url_;
};

void read_xml(std::string const & filename, xml_node &node)
{
    libxml2_loader loader;
    loader.load(filename, node);
}
void read_xml_string(std::string const & str, xml_node &node, std::string const & base_path)
{
    libxml2_loader loader;
    loader.load_string(str, node, base_path);
}

} // end of namespace mapnik

#endif
<|endoftext|>


<commit_before>#ifdef WIN32
	#include <windows.h>
#endif

#include <stdio.h>
#include <time.h>
#include <string.h>

#include "../Shared/Core/SharedQueue.h"

#define MQ_MAXMSG	1000
#define MSG_SIZE	1500
#define QUEUE_NAME	"queue"

#define CLK2S(clk)	(double(clk)/CLOCKS_PER_SEC)

void sleepMicro(unsigned long usecs)
{
#ifdef WIN32
	DWORD msec = (DWORD)(usecs/1000);
	Sleep(msec);
#else
	struct timespec tm;
	tm.tv_sec = (unsigned long long)usecs/1000000;
	tm.tv_nsec = (unsigned long long)usecs * 1000 - (unsigned long long)tm.tv_sec * 1000000000UL;
	clock_nanosleep(CLOCK_MONOTONIC, 0, &tm, NULL);
#endif
}

//==============================================================================
static int sendFunc()
{
	clock_t				prevTS, currTS;
	char				msg[MSG_SIZE] = {};
	unsigned int		prev = 0;
	unsigned int		counter = 0;
	unsigned int		*pCounter = (unsigned int*)msg;
	unsigned int		*pEndCounter = (unsigned int*)(msg + sizeof(msg) - sizeof(unsigned int));
	TSPSCSharedQueue	sendQueue;

	if (!sendQueue.open(QUEUE_NAME, MSG_SIZE, MQ_MAXMSG))
	{
		perror("SENDER. Unable to open send queue.");
		return -1;
	}

	prevTS = clock();
	while(1)
	{
		bool res = sendQueue.push(sizeof(msg), msg);
		if (!res)
		{
			sleepMicro(0);
			continue;
		}

		*pCounter = counter;
		*pEndCounter = counter;
		++counter;
		if (counter%1000000==0)
		{
			double p;
			currTS = clock();
			p = CLK2S(currTS - prevTS);
			if (p==0)
				p = 0.00000000001;
			prevTS = currTS;
			printf("%g [msg/s]\n", (counter-prev)/p);
			prev = counter;
		}

	}
	return -1;
}

//==============================================================================
static int recvFunc()
{
	char				msg[MSG_SIZE] = {};
	unsigned int		prev = 0;
	unsigned int		*pCounter = (unsigned int*)msg;
	unsigned int		*pEndCounter = (unsigned int*)(msg + sizeof(msg) - sizeof(unsigned int));
	TSPSCSharedQueue	recvQueue;

	if (!recvQueue.open(QUEUE_NAME, MSG_SIZE, MQ_MAXMSG, true))
	{
		perror("RECEIVER. Unable to open recv queue.");
		return -1;
	}

	while(1)
	{
		size_t res = recvQueue.pop(msg);
		if (res<=0)
		{
			sleepMicro(0);
			continue;
		}

		if (*pCounter!=*pEndCounter)
		{
			printf("%u!=%u\n", *pCounter, *pEndCounter);
		}

		if (prev+1!=*pCounter)
		{
			printf("SEQ. %u %u\n", *pCounter, prev);
		}
		prev = *pCounter;
		if (*pCounter%100000==0)
		{
			printf("%u\n", *pCounter);
		}
	}

	return -1;
}

//==============================================================================
int main(int argc, char *argv[])
{
	printf("SharedQueueTest -send|-recv\n");
	if (argc>1 && strcmp(argv[1], "-send")==0)
	{
		return sendFunc();
	}
	if (argc>1 && strcmp(argv[1], "-recv")==0)
	{
		return recvFunc();
	}

	return -1;
}

<commit_msg>Update main.cpp<commit_after>#ifdef WIN32
	#include <windows.h>
#endif

#include <stdio.h>
#include <time.h>
#include <string.h>

#include "../Src/SharedQueue.h"

#define MQ_MAXMSG	1000
#define MSG_SIZE	1500
#define QUEUE_NAME	"queue"

#define CLK2S(clk)	(double(clk)/CLOCKS_PER_SEC)

void sleepMicro(unsigned long usecs)
{
#ifdef WIN32
	DWORD msec = (DWORD)(usecs/1000);
	Sleep(msec);
#else
	struct timespec tm;
	tm.tv_sec = (unsigned long long)usecs/1000000;
	tm.tv_nsec = (unsigned long long)usecs * 1000 - (unsigned long long)tm.tv_sec * 1000000000UL;
	clock_nanosleep(CLOCK_MONOTONIC, 0, &tm, NULL);
#endif
}

//==============================================================================
static int sendFunc()
{
	clock_t				prevTS, currTS;
	char				msg[MSG_SIZE] = {};
	unsigned int		prev = 0;
	unsigned int		counter = 0;
	unsigned int		*pCounter = (unsigned int*)msg;
	unsigned int		*pEndCounter = (unsigned int*)(msg + sizeof(msg) - sizeof(unsigned int));
	TSPSCSharedQueue	sendQueue;

	if (!sendQueue.open(QUEUE_NAME, MSG_SIZE, MQ_MAXMSG))
	{
		perror("SENDER. Unable to open send queue.");
		return -1;
	}

	prevTS = clock();
	while(1)
	{
		bool res = sendQueue.push(sizeof(msg), msg);
		if (!res)
		{
			sleepMicro(0);
			continue;
		}

		*pCounter = counter;
		*pEndCounter = counter;
		++counter;
		if (counter%1000000==0)
		{
			double p;
			currTS = clock();
			p = CLK2S(currTS - prevTS);
			if (p==0)
				p = 0.00000000001;
			prevTS = currTS;
			printf("%g [msg/s]\n", (counter-prev)/p);
			prev = counter;
		}

	}
	return -1;
}

//==============================================================================
static int recvFunc()
{
	char				msg[MSG_SIZE] = {};
	unsigned int		prev = 0;
	unsigned int		*pCounter = (unsigned int*)msg;
	unsigned int		*pEndCounter = (unsigned int*)(msg + sizeof(msg) - sizeof(unsigned int));
	TSPSCSharedQueue	recvQueue;

	if (!recvQueue.open(QUEUE_NAME, MSG_SIZE, MQ_MAXMSG, true))
	{
		perror("RECEIVER. Unable to open recv queue.");
		return -1;
	}

	while(1)
	{
		size_t res = recvQueue.pop(msg);
		if (res<=0)
		{
			sleepMicro(0);
			continue;
		}

		if (*pCounter!=*pEndCounter)
		{
			printf("%u!=%u\n", *pCounter, *pEndCounter);
		}

		if (prev+1!=*pCounter)
		{
			printf("SEQ. %u %u\n", *pCounter, prev);
		}
		prev = *pCounter;
		if (*pCounter%100000==0)
		{
			printf("%u\n", *pCounter);
		}
	}

	return -1;
}

//==============================================================================
int main(int argc, char *argv[])
{
	printf("SharedQueueTest -send|-recv\n");
	if (argc>1 && strcmp(argv[1], "-send")==0)
	{
		return sendFunc();
	}
	if (argc>1 && strcmp(argv[1], "-recv")==0)
	{
		return recvFunc();
	}

	return -1;
}

<|endoftext|>


<commit_before>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup()
{
    ofHideCursor();
    //ofSetFullscreen(true);
    ofSetBackgroundColor(0);
}

//--------------------------------------------------------------
void ofApp::update()
{
    Hexagon.update();
}

//--------------------------------------------------------------
void ofApp::draw()
{
    Hexagon.draw();
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

    // Toggle previewmode (not yet implemented)
    if(key == 'p'){
        Hexagon.togglePreviewMode();
    }

    // load preview scene
    if(key == 'l'){
        Hexagon.loadPreviewScene();
    }

}
<commit_msg>set to fullscreen<commit_after>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup()
{
    ofHideCursor();
    ofSetFullscreen(true);
    ofSetBackgroundColor(0);
}

//--------------------------------------------------------------
void ofApp::update()
{
    Hexagon.update();
}

//--------------------------------------------------------------
void ofApp::draw()
{
    Hexagon.draw();
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

    // Toggle previewmode (not yet implemented)
    if(key == 'p'){
        Hexagon.togglePreviewMode();
    }

    // load preview scene
    if(key == 'l'){
        Hexagon.loadPreviewScene();
    }

}
<|endoftext|>


<commit_before>#include <iostream>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
using namespace std;

void ls(char **argv, int flag, char directory[]){

	DIR *dirp;
	if(!(dirp = opendir(directory))){
		perror("Opendir erro");
		return;
	}

	dirent *direntp;
	while((direntp = readdir(dirp))){

		if(errno != 0){
			 perror ("Readdir erro");
			return;
		}

		//flag 0 means that no flag was set, display regular LS function
		if(flag==0){
			//avoid files starting with .
			if(direntp->d_name[0]!='.')
				cout<<direntp->d_name<<"  ";
		}else{

		}

	}
	cout<<endl;
	closedir(dirp);
}

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

	char * find_flag;
	int flag=0;
	string path_folder="";

	//in case first parameter is not 'ls'
	if(memcmp(argv[1],"ls",2)!=0){
		cout<<"command not valid"<<endl;
		return 0;
	}

	for(int i=2; i<argc; i++){
		//checking how many flag are passed
		if(memcmp(argv[i],"-",1)==0){
			find_flag = strchr(argv[i],'l');
			if(find_flag != NULL){
				flag+= 1;
			}
			find_flag = strchr(argv[i],'a');
			if(find_flag != NULL){
				flag+=2;
			}
			find_flag = strchr(argv[i],'R');
			if(find_flag != NULL){
				flag+=4;
			}
		}else{
			//recieving folder as argument
			path_folder = argv[i];
		}
	}
	//if no folder has been passed as argument
	if(path_folder=="") path_folder = get_current_dir_name();

	char * directory = new char[path_folder.length()+1];
	strcpy(directory, path_folder.c_str());

	ls(argv, flag, directory);

	delete[] directory;

	return 0;
}
<commit_msg>ls function organized in a switch statement, ls -a working<commit_after>#include <iostream>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
using namespace std;

void ls(char **argv, int flag, char directory[]){

	DIR *dirp;
	if(!(dirp = opendir(directory))){
		perror("Opendir erro");
		return;
	}

	dirent *direntp;
	while((direntp = readdir(dirp))){

		if(errno != 0){
			 perror ("Readdir erro");
			return;
		}

		switch(flag){
			//ls
			case 0:
				//avoid files starting with .
				if(direntp->d_name[0]!='.')
					cout<<direntp->d_name<<"  ";
			break;

			//ls -a
			case 1:
				cout<<direntp->d_name<<"  ";
			break;

			//ls -l
			case 2:
			break;

			//ls -al
			case 3:
			break;

			//ls -R
			case 4:
			break;

			//ls -aR
			case 5:
			break;

			//ls -lR
			case 6:
			break;

			//ls -laR
			case 7:
			break;
		}

	}
	cout<<endl;
	closedir(dirp);
}

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

	char * find_flag;
	int flag=0;
	string path_folder="";

	//in case first parameter is not 'ls'
	if(memcmp(argv[1],"ls",2)!=0){
		cout<<"command not valid"<<endl;
		return 0;
	}

	for(int i=2; i<argc; i++){
		//checking how many flag are passed
		if(memcmp(argv[i],"-",1)==0){
			find_flag = strchr(argv[i],'a');
			if(find_flag != NULL){
				flag+= 1;
			}
			find_flag = strchr(argv[i],'l');
			if(find_flag != NULL){
				flag+=2;
			}
			find_flag = strchr(argv[i],'R');
			if(find_flag != NULL){
				flag+=4;
			}
		}else{
			//recieving folder as argument
			path_folder = argv[i];
		}
	}
	//if no folder has been passed as argument
	if(path_folder=="") path_folder = get_current_dir_name();

	char * directory = new char[path_folder.length()+1];
	strcpy(directory, path_folder.c_str());

	ls(argv, flag, directory);

	delete[] directory;

	return 0;
}
<|endoftext|>


<commit_before>#include <cstring>	/// for memset

#include "zlog/zlog.hpp"

#include "exemodel/wsserveree.hpp"

namespace exemodel {

class wsee final : public pollee {
public:
	wsee() = default;
	~wsee() = default;

	int init(struct lws * wsi, struct lws_context * context, int fd, uint32_t evts)
	{
		savefd(fd);
		saveevts(evts);
		m_wsi = wsi;
		m_context = context;
		return 0;
	}

	virtual int dispose(poller & /*mgr*/, uint32_t evts)
	{
		struct pollfd i = {
			this->fd(),
			(short)this->evts(),
			(short)evts
		};
		lws_service_fd(m_context, &i);
		return 0;
	}

	int sendTextMessage(void *buf, size_t len)
	{
		return lws_write(m_wsi, (unsigned char *)buf, len, LWS_WRITE_TEXT);
	}

	int sendBinaryMessage(void *buf, size_t len)
	{
		return lws_write(m_wsi, (unsigned char *)buf, len, LWS_WRITE_BINARY);
	}
private:
	struct lws * m_wsi;
	struct lws_context * m_context;
};

int wsserveree::callback_http(
	struct lws *wsi,
	enum lws_callback_reasons reason,
	void */*user*/,
	void *in,
	size_t len)
{
	struct lws_context * context = lws_get_context(wsi);
	wsserveree * svr = (wsserveree *)lws_context_user(context);

	int ret = 0;
	switch (reason) {
	case LWS_CALLBACK_ESTABLISHED:
		ret = svr->__receiveConnectState(wsi, true);
		break;

	case LWS_CALLBACK_CLOSED:
		ret = svr->__receiveConnectState(wsi, false);
		break;

	case LWS_CALLBACK_ADD_POLL_FD: {
			struct lws_pollargs & pa = *(struct lws_pollargs *)in;
			//printf("wsi(%p) fd(%d)\n", (void*)wsi, pa.fd);
			zlog_debug("add poll fd: %#x %d", (unsigned long)wsi, pa.fd);
			svr->__addSp(wsi, context, pa.fd, pa.events);
		}
		break;

	case LWS_CALLBACK_DEL_POLL_FD: {
			struct lws_pollargs & pa = *(struct lws_pollargs *)in;
			zlog_debug("del poll fd: %#x %d", (unsigned long)wsi, pa.fd);
			svr->__delSp(wsi, pa.fd);
		}
		break;

	case LWS_CALLBACK_CHANGE_MODE_POLL_FD: {
			struct lws_pollargs & pa = *(struct lws_pollargs *)in;
			svr->__modSp(wsi, pa.fd, pa.events);
		}
		break;

	case LWS_CALLBACK_RECEIVE: {
			const size_t remaining = lws_remaining_packet_payload(wsi);
			const bool is_final = lws_is_final_fragment(wsi);
			if (remaining == 0 && is_final) {
				//char namebuf[200];
				//printf("receive from %s\n", lws_get_peer_simple(wsi, namebuf, sizeof(namebuf)));
				const bool is_binary = lws_frame_is_binary(wsi);
				if (is_binary) {
					svr->__receiveBinaryMessage(wsi, in, len);
				}
				else {
					svr->__receiveTextMessage(wsi, in, len);
				}
			}
		}
		break;
	default:
		break;
	}

	return ret;
}

struct lws_protocols wsserveree::protocols[] = {
	{
		"http-only",		/* name */
		wsserveree::callback_http,		/* callback */
		0,	/* per_session_data_size */
		256*1024,			/* max frame size / rx buffer */
		0,
		nullptr,
		0
	},
	{ nullptr, nullptr, 0, 0, 0, nullptr, 0 } /* terminator */
};

int wsserveree::init(uint16_t port)
{
	int ret = 0;
	ret = poller::init();
	if (ret == -1)
		return ret;

	struct lws_context_creation_info info;
	std::memset(&info, 0, sizeof(info));

	info.port = port;
	info.gid = -1;
	info.uid = -1;
	info.max_http_header_pool = 16;
	info.protocols = protocols;
	info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
	info.timeout_secs = 5;
	info.user = this;

	m_pcontext = lws_create_context(&info);
	if (!m_pcontext) {
		return -1;
	}

	return 0;
}

wsserveree::~wsserveree()
{
	if (m_pcontext) {
		lws_context_destroy(m_pcontext);
		m_pcontext = nullptr;
	}
}

int wsserveree::sendTextMessage(cid wsi, void * buffer, size_t length)
{
	wsee * pD = m_sps.at(wsi);
	return pD->sendTextMessage(buffer, length);
}

int wsserveree::sendBinaryMessage(cid wsi, void * buffer, size_t length)
{
	wsee * pD = m_sps.at(wsi);
	return pD->sendBinaryMessage(buffer, length);
}

void wsserveree::bind4TextMessage(msg_cb_t cb)
{
	m_rxTextCallback = cb;
}

void wsserveree::bind4BinaryMessage(msg_cb_t cb)
{
	m_rxBinaryCallback = cb;
}

void wsserveree::bind4StateChange(state_cb_t cb)
{
	m_stateChangeCallback = cb;
}

void wsserveree::__addSp(cid wsi, struct lws_context *context, int fd, uint32_t events)
{
	wsee * newSp = new wsee();
	int ret = newSp->init(wsi, context, fd, events);
	if (ret < 0) {
		delete newSp;
		return;
	}

	m_sps.insert(std::make_pair(wsi, newSp));
	this->add(*newSp);
}

void wsserveree::__delSp(cid wsi, int fd)
{
	wsee * pD = m_sps.at(wsi);
	if (fd != pD->fd()) {
		zlog_err("wsserveree: error fd(%d) for delete", fd);
	}
	this->del(*pD);
	m_sps.erase(wsi);
	delete pD;
}

void wsserveree::__modSp(cid wsi, int fd, uint32_t events)
{
	wsee * pD = m_sps.at(wsi);
	if (fd != pD->fd()) {
		zlog_err("wsserveree: error fd(%d) for modify", fd);
	}

	pD->saveevts(events);
	this->mod(*pD);
}

int wsserveree::__receiveTextMessage(cid wsi, void * data, size_t len)
{
	//wsee * pD = m_sps.at(wsi);
	if (m_rxTextCallback) {
		return m_rxTextCallback(wsi, data, len);
	}
	return 0;
}

int wsserveree::__receiveBinaryMessage(cid wsi, void * data, size_t len)
{
	if (m_rxBinaryCallback) {
		return m_rxBinaryCallback(wsi, data, len);
	}
	return 0;
}

int wsserveree::__receiveConnectState(cid wsi, bool isConnecting)
{
	if (m_stateChangeCallback) {
		return m_stateChangeCallback(wsi, isConnecting);
	}
	return 0;
}

void wsserveree::unbind()
{
	m_rxTextCallback = nullptr;
	m_rxBinaryCallback = nullptr;
	m_stateChangeCallback = nullptr;
}

}
<commit_msg>fix string format for zlog call<commit_after>#include <cstring>	/// for memset

#include "zlog/zlog.hpp"

#include "exemodel/wsserveree.hpp"

namespace exemodel {

class wsee final : public pollee {
public:
	wsee() = default;
	~wsee() = default;

	int init(struct lws * wsi, struct lws_context * context, int fd, uint32_t evts)
	{
		savefd(fd);
		saveevts(evts);
		m_wsi = wsi;
		m_context = context;
		return 0;
	}

	virtual int dispose(poller & /*mgr*/, uint32_t evts)
	{
		struct pollfd i = {
			this->fd(),
			(short)this->evts(),
			(short)evts
		};
		lws_service_fd(m_context, &i);
		return 0;
	}

	int sendTextMessage(void *buf, size_t len)
	{
		return lws_write(m_wsi, (unsigned char *)buf, len, LWS_WRITE_TEXT);
	}

	int sendBinaryMessage(void *buf, size_t len)
	{
		return lws_write(m_wsi, (unsigned char *)buf, len, LWS_WRITE_BINARY);
	}
private:
	struct lws * m_wsi;
	struct lws_context * m_context;
};

int wsserveree::callback_http(
	struct lws *wsi,
	enum lws_callback_reasons reason,
	void */*user*/,
	void *in,
	size_t len)
{
	struct lws_context * context = lws_get_context(wsi);
	wsserveree * svr = (wsserveree *)lws_context_user(context);

	int ret = 0;
	switch (reason) {
	case LWS_CALLBACK_ESTABLISHED:
		ret = svr->__receiveConnectState(wsi, true);
		break;

	case LWS_CALLBACK_CLOSED:
		ret = svr->__receiveConnectState(wsi, false);
		break;

	case LWS_CALLBACK_ADD_POLL_FD: {
			struct lws_pollargs & pa = *(struct lws_pollargs *)in;
			//printf("wsi(%p) fd(%d)\n", (void*)wsi, pa.fd);
			zlog_debug("add poll fd: %#lx %d", (unsigned long)wsi, pa.fd);
			svr->__addSp(wsi, context, pa.fd, pa.events);
		}
		break;

	case LWS_CALLBACK_DEL_POLL_FD: {
			struct lws_pollargs & pa = *(struct lws_pollargs *)in;
			zlog_debug("del poll fd: %#lx %d", (unsigned long)wsi, pa.fd);
			svr->__delSp(wsi, pa.fd);
		}
		break;

	case LWS_CALLBACK_CHANGE_MODE_POLL_FD: {
			struct lws_pollargs & pa = *(struct lws_pollargs *)in;
			svr->__modSp(wsi, pa.fd, pa.events);
		}
		break;

	case LWS_CALLBACK_RECEIVE: {
			const size_t remaining = lws_remaining_packet_payload(wsi);
			const bool is_final = lws_is_final_fragment(wsi);
			if (remaining == 0 && is_final) {
				//char namebuf[200];
				//printf("receive from %s\n", lws_get_peer_simple(wsi, namebuf, sizeof(namebuf)));
				const bool is_binary = lws_frame_is_binary(wsi);
				if (is_binary) {
					svr->__receiveBinaryMessage(wsi, in, len);
				}
				else {
					svr->__receiveTextMessage(wsi, in, len);
				}
			}
		}
		break;
	default:
		break;
	}

	return ret;
}

struct lws_protocols wsserveree::protocols[] = {
	{
		"http-only",		/* name */
		wsserveree::callback_http,		/* callback */
		0,	/* per_session_data_size */
		256*1024,			/* max frame size / rx buffer */
		0,
		nullptr,
		0
	},
	{ nullptr, nullptr, 0, 0, 0, nullptr, 0 } /* terminator */
};

int wsserveree::init(uint16_t port)
{
	int ret = 0;
	ret = poller::init();
	if (ret == -1)
		return ret;

	struct lws_context_creation_info info;
	std::memset(&info, 0, sizeof(info));

	info.port = port;
	info.gid = -1;
	info.uid = -1;
	info.max_http_header_pool = 16;
	info.protocols = protocols;
	info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
	info.timeout_secs = 5;
	info.user = this;

	m_pcontext = lws_create_context(&info);
	if (!m_pcontext) {
		return -1;
	}

	return 0;
}

wsserveree::~wsserveree()
{
	if (m_pcontext) {
		lws_context_destroy(m_pcontext);
		m_pcontext = nullptr;
	}
}

int wsserveree::sendTextMessage(cid wsi, void * buffer, size_t length)
{
	wsee * pD = m_sps.at(wsi);
	return pD->sendTextMessage(buffer, length);
}

int wsserveree::sendBinaryMessage(cid wsi, void * buffer, size_t length)
{
	wsee * pD = m_sps.at(wsi);
	return pD->sendBinaryMessage(buffer, length);
}

void wsserveree::bind4TextMessage(msg_cb_t cb)
{
	m_rxTextCallback = cb;
}

void wsserveree::bind4BinaryMessage(msg_cb_t cb)
{
	m_rxBinaryCallback = cb;
}

void wsserveree::bind4StateChange(state_cb_t cb)
{
	m_stateChangeCallback = cb;
}

void wsserveree::__addSp(cid wsi, struct lws_context *context, int fd, uint32_t events)
{
	wsee * newSp = new wsee();
	int ret = newSp->init(wsi, context, fd, events);
	if (ret < 0) {
		delete newSp;
		return;
	}

	m_sps.insert(std::make_pair(wsi, newSp));
	this->add(*newSp);
}

void wsserveree::__delSp(cid wsi, int fd)
{
	wsee * pD = m_sps.at(wsi);
	if (fd != pD->fd()) {
		zlog_err("wsserveree: error fd(%d) for delete", fd);
	}
	this->del(*pD);
	m_sps.erase(wsi);
	delete pD;
}

void wsserveree::__modSp(cid wsi, int fd, uint32_t events)
{
	wsee * pD = m_sps.at(wsi);
	if (fd != pD->fd()) {
		zlog_err("wsserveree: error fd(%d) for modify", fd);
	}

	pD->saveevts(events);
	this->mod(*pD);
}

int wsserveree::__receiveTextMessage(cid wsi, void * data, size_t len)
{
	//wsee * pD = m_sps.at(wsi);
	if (m_rxTextCallback) {
		return m_rxTextCallback(wsi, data, len);
	}
	return 0;
}

int wsserveree::__receiveBinaryMessage(cid wsi, void * data, size_t len)
{
	if (m_rxBinaryCallback) {
		return m_rxBinaryCallback(wsi, data, len);
	}
	return 0;
}

int wsserveree::__receiveConnectState(cid wsi, bool isConnecting)
{
	if (m_stateChangeCallback) {
		return m_stateChangeCallback(wsi, isConnecting);
	}
	return 0;
}

void wsserveree::unbind()
{
	m_rxTextCallback = nullptr;
	m_rxBinaryCallback = nullptr;
	m_stateChangeCallback = nullptr;
}

}
<|endoftext|>


<commit_before>/**
 * @file   ErrPair.hpp
 * @brief  ErrPair class prototype.
 * @author zer0
 * @date   2019-09-11
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_ERRPAIR_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_ERRPAIR_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/Err.hpp>

#include <type_traits>
#include <string>
#include <ostream>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

/**
 * ErrPair class template.
 *
 * @author zer0
 * @date   2019-09-11
 */
template <typename T>
struct ErrPair
{
    using ValueType = T;

    static_assert(!std::is_void<ValueType>::value, "Void type is not supported.");
    static_assert(!std::is_reference<ValueType>::value, "Reference type is not supported.");

    Err code;
    ValueType value;

    TBAG_CONSTEXPR static bool const nothrow_def = std::is_nothrow_default_constructible<ValueType>::value;
    TBAG_CONSTEXPR static bool const nothrow_copy = std::is_nothrow_copy_constructible<ValueType>::value;
    TBAG_CONSTEXPR static bool const nothrow_move = std::is_nothrow_move_constructible<ValueType>::value;
    TBAG_CONSTEXPR static bool const nothrow_copy_assign = std::is_nothrow_copy_assignable<ValueType>::value;
    TBAG_CONSTEXPR static bool const nothrow_move_assign = std::is_nothrow_move_assignable<ValueType>::value;

    ErrPair() TBAG_NOEXCEPT_SPECIFIER(nothrow_def)
            : code(E_UNKNOWN), value()
    { /* EMPTY. */ }
    ErrPair(Err c) TBAG_NOEXCEPT_SPECIFIER(nothrow_def)
            : code(c), value()
    { /* EMPTY. */ }

    ErrPair(ValueType const & v) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy)
            : code(E_UNKNOWN), value(v)
    { /* EMPTY. */ }
    ErrPair(Err c, ValueType const & v) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy)
            : code(c), value(v)
    { /* EMPTY. */ }

    ErrPair(ValueType && v) TBAG_NOEXCEPT_SPECIFIER(nothrow_move)
            : code(E_UNKNOWN), value(std::move(v))
    { /* EMPTY. */ }
    ErrPair(Err c, ValueType && v) TBAG_NOEXCEPT_SPECIFIER(nothrow_move)
            : code(c), value(std::move(v))
    { /* EMPTY. */ }

    ErrPair(ErrPair const & obj) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy)
            : code(obj.code), value(obj.value)
    { /* EMPTY. */ }
    ErrPair(ErrPair && obj) TBAG_NOEXCEPT_SPECIFIER(nothrow_move)
            : code(obj.code), value(std::move(obj.value))
    { /* EMPTY. */ }

    ~ErrPair()
    { /* EMPTY. */ }

    ErrPair & operator =(Err c) TBAG_NOEXCEPT
    {
        code = c;
        return *this;
    }

    ErrPair & operator =(ValueType const & v) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy_assign)
    {
        value = v;
        return *this;
    }

    ErrPair & operator =(ValueType && v) TBAG_NOEXCEPT_SPECIFIER(nothrow_move_assign)
    {
        value = std::move(v);
        return *this;
    }

    ErrPair & operator =(ErrPair const & obj) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy_assign)
    {
        if (this != &obj) {
            code = obj.code;
            value = obj.value;
        }
        return *this;
    }

    ErrPair & operator =(ErrPair && obj) TBAG_NOEXCEPT_SPECIFIER(nothrow_move_assign)
    {
        if (this != &obj) {
            code = obj.code;
            value = std::move(obj.value);
        }
        return *this;
    }

    char const * name() const TBAG_NOEXCEPT
    {
        return libtbag::getErrName(code);
    }

    char const * detail() const TBAG_NOEXCEPT
    {
        return libtbag::getErrDetail(code);
    }

    inline operator Err() const TBAG_NOEXCEPT
    {
        return code;
    }

    inline operator bool() const TBAG_NOEXCEPT
    {
        return isSuccess(code);
    }

    inline int toInt() const TBAG_NOEXCEPT
    {
        return static_cast<int>(code);
    }

    inline void fromInt(int v) TBAG_NOEXCEPT
    {
        code = static_cast<Err>(v);
    }

    template <class CharT, class TraitsT>
    friend std::basic_ostream<CharT, TraitsT> & operator<<(std::basic_ostream<CharT, TraitsT> & os, ErrPair const & err)
    {
        return os << err.name();
    }
};

/**
 * ErrMsgPair class template.
 *
 * @author zer0
 * @date   2019-11-11
 */
template <typename T>
struct ErrMsgPair : public ErrPair<T>
{
    using ValueType = typename ErrPair<T>::ValueType;

    std::string msg;

    ErrMsgPair() : ErrPair<T>()
    { /* EMPTY. */ }
    ErrMsgPair(Err c) : ErrPair<T>(c)
    { /* EMPTY. */ }

    ErrMsgPair(ValueType const & v) : ErrPair<T>(v)
    { /* EMPTY. */ }
    ErrMsgPair(Err c, ValueType const & v) : ErrPair<T>(c, v)
    { /* EMPTY. */ }

    ErrMsgPair(ValueType && v) : ErrPair<T>(std::move(v))
    { /* EMPTY. */ }
    ErrMsgPair(Err c, ValueType && v) : ErrPair<T>(c, std::move(v))
    { /* EMPTY. */ }

    ErrMsgPair(ErrMsgPair const & obj) : ErrPair<T>(obj), msg(obj.msg)
    { /* EMPTY. */ }
    ErrMsgPair(ErrMsgPair && obj) TBAG_NOEXCEPT : ErrPair<T>(std::move(obj)), msg(std::move(obj.msg))
    { /* EMPTY. */ }

    ~ErrMsgPair()
    { /* EMPTY. */ }

    ErrMsgPair & operator =(ErrMsgPair const & obj)
    {
        if (this != &obj) {
            ErrPair<T>::operator =(obj);
            msg = obj.msg;
        }
        return *this;
    }

    ErrMsgPair & operator =(ErrMsgPair && obj) TBAG_NOEXCEPT
    {
        if (this != &obj) {
            ErrPair<T>::operator =(std::move(obj));
            msg = std::move(obj.msg);
        }
        return *this;
    }
};

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_ERRPAIR_HPP__

<commit_msg>Update ErrMsgPair class template.<commit_after>/**
 * @file   ErrPair.hpp
 * @brief  ErrPair class prototype.
 * @author zer0
 * @date   2019-09-11
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_ERRPAIR_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_ERRPAIR_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/predef.hpp>
#include <libtbag/Err.hpp>

#include <type_traits>
#include <string>
#include <ostream>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

/**
 * ErrPair class template.
 *
 * @author zer0
 * @date   2019-09-11
 */
template <typename T>
struct ErrPair
{
    using ValueType = T;

    static_assert(!std::is_void<ValueType>::value, "Void type is not supported.");
    static_assert(!std::is_reference<ValueType>::value, "Reference type is not supported.");

    Err code;
    ValueType value;

    TBAG_CONSTEXPR static bool const nothrow_def = std::is_nothrow_default_constructible<ValueType>::value;
    TBAG_CONSTEXPR static bool const nothrow_copy = std::is_nothrow_copy_constructible<ValueType>::value;
    TBAG_CONSTEXPR static bool const nothrow_move = std::is_nothrow_move_constructible<ValueType>::value;
    TBAG_CONSTEXPR static bool const nothrow_copy_assign = std::is_nothrow_copy_assignable<ValueType>::value;
    TBAG_CONSTEXPR static bool const nothrow_move_assign = std::is_nothrow_move_assignable<ValueType>::value;

    ErrPair() TBAG_NOEXCEPT_SPECIFIER(nothrow_def)
            : code(E_UNKNOWN), value()
    { /* EMPTY. */ }
    ErrPair(Err c) TBAG_NOEXCEPT_SPECIFIER(nothrow_def)
            : code(c), value()
    { /* EMPTY. */ }

    ErrPair(ValueType const & v) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy)
            : code(E_UNKNOWN), value(v)
    { /* EMPTY. */ }
    ErrPair(Err c, ValueType const & v) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy)
            : code(c), value(v)
    { /* EMPTY. */ }

    ErrPair(ValueType && v) TBAG_NOEXCEPT_SPECIFIER(nothrow_move)
            : code(E_UNKNOWN), value(std::move(v))
    { /* EMPTY. */ }
    ErrPair(Err c, ValueType && v) TBAG_NOEXCEPT_SPECIFIER(nothrow_move)
            : code(c), value(std::move(v))
    { /* EMPTY. */ }

    ErrPair(ErrPair const & obj) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy)
            : code(obj.code), value(obj.value)
    { /* EMPTY. */ }
    ErrPair(ErrPair && obj) TBAG_NOEXCEPT_SPECIFIER(nothrow_move)
            : code(obj.code), value(std::move(obj.value))
    { /* EMPTY. */ }

    ~ErrPair()
    { /* EMPTY. */ }

    ErrPair & operator =(Err c) TBAG_NOEXCEPT
    {
        code = c;
        return *this;
    }

    ErrPair & operator =(ValueType const & v) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy_assign)
    {
        value = v;
        return *this;
    }

    ErrPair & operator =(ValueType && v) TBAG_NOEXCEPT_SPECIFIER(nothrow_move_assign)
    {
        value = std::move(v);
        return *this;
    }

    ErrPair & operator =(ErrPair const & obj) TBAG_NOEXCEPT_SPECIFIER(nothrow_copy_assign)
    {
        if (this != &obj) {
            code = obj.code;
            value = obj.value;
        }
        return *this;
    }

    ErrPair & operator =(ErrPair && obj) TBAG_NOEXCEPT_SPECIFIER(nothrow_move_assign)
    {
        if (this != &obj) {
            code = obj.code;
            value = std::move(obj.value);
        }
        return *this;
    }

    char const * name() const TBAG_NOEXCEPT
    {
        return libtbag::getErrName(code);
    }

    char const * detail() const TBAG_NOEXCEPT
    {
        return libtbag::getErrDetail(code);
    }

    inline operator Err() const TBAG_NOEXCEPT
    {
        return code;
    }

    inline operator bool() const TBAG_NOEXCEPT
    {
        return isSuccess(code);
    }

    inline int toInt() const TBAG_NOEXCEPT
    {
        return static_cast<int>(code);
    }

    inline void fromInt(int v) TBAG_NOEXCEPT
    {
        code = static_cast<Err>(v);
    }

    template <class CharT, class TraitsT>
    friend std::basic_ostream<CharT, TraitsT> & operator<<(std::basic_ostream<CharT, TraitsT> & os, ErrPair const & err)
    {
        return os << err.name();
    }
};

/**
 * ErrMsgPair class template.
 *
 * @author zer0
 * @date   2019-11-11
 */
template <typename T>
struct ErrMsgPair : public ErrPair<T>
{
    using BaseErrPair = ErrPair<T>;
    using ValueType = typename BaseErrPair::ValueType;

    TBAG_CONSTEXPR static bool const base_nothrow_move = std::is_nothrow_move_constructible<BaseErrPair>::value;
    TBAG_CONSTEXPR static bool const base_nothrow_move_assign = std::is_nothrow_move_assignable<BaseErrPair>::value;

    TBAG_CONSTEXPR static bool const str_nothrow_move = std::is_nothrow_move_constructible<std::string>::value;
    TBAG_CONSTEXPR static bool const str_nothrow_move_assign = std::is_nothrow_move_assignable<std::string>::value;

    std::string msg;

    ErrMsgPair() : ErrPair<T>()
    { /* EMPTY. */ }
    ErrMsgPair(Err c) : ErrPair<T>(c)
    { /* EMPTY. */ }

    ErrMsgPair(ValueType const & v) : ErrPair<T>(v)
    { /* EMPTY. */ }
    ErrMsgPair(Err c, ValueType const & v) : ErrPair<T>(c, v)
    { /* EMPTY. */ }

    ErrMsgPair(ValueType && v) : ErrPair<T>(std::move(v))
    { /* EMPTY. */ }
    ErrMsgPair(Err c, ValueType && v) : ErrPair<T>(c, std::move(v))
    { /* EMPTY. */ }

    ErrMsgPair(ErrMsgPair const & obj) : ErrPair<T>(obj), msg(obj.msg)
    { /* EMPTY. */ }
    ErrMsgPair(ErrMsgPair && obj) TBAG_NOEXCEPT_SPECIFIER(base_nothrow_move && str_nothrow_move)
            : ErrPair<T>(std::move(obj)), msg(std::move(obj.msg))
    { /* EMPTY. */ }

    ~ErrMsgPair()
    { /* EMPTY. */ }

    ErrMsgPair & operator =(ErrMsgPair const & obj)
    {
        if (this != &obj) {
            ErrPair<T>::operator =(obj);
            msg = obj.msg;
        }
        return *this;
    }

    ErrMsgPair & operator =(ErrMsgPair && obj) TBAG_NOEXCEPT_SPECIFIER(base_nothrow_move_assign && str_nothrow_move_assign)
    {
        if (this != &obj) {
            ErrPair<T>::operator =(std::move(obj));
            msg = std::move(obj.msg);
        }
        return *this;
    }
};

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_ERRPAIR_HPP__

<|endoftext|>