Skip to content

Commit

Permalink
New TCP server
Browse files Browse the repository at this point in the history
  • Loading branch information
jezal committed Sep 15, 2014
1 parent 6b1858d commit 6d74194
Show file tree
Hide file tree
Showing 15 changed files with 950 additions and 1 deletion.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ if(STATIC)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON)
endif()
find_package(Boost 1.53 REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options)
find_package(Boost 1.53 REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options coroutine context)
if((${Boost_MAJOR_VERSION} EQUAL 1) AND (${Boost_MINOR_VERSION} EQUAL 54))
message(SEND_ERROR "Boost version 1.54 is unsupported, more details are available here http://goo.gl/RrCFmA")
endif()
Expand Down
98 changes: 98 additions & 0 deletions src/System/Event.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
//
// This file is part of Bytecoin.
//
// Bytecoin 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 3 of the License, or
// (at your option) any later version.
//
// Bytecoin 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 Bytecoin. If not, see <http://www.gnu.org/licenses/>.

#include "Event.h"
#include <cassert>
#include "System.h"

struct Event::Waiter {
Event::Waiter* next;
void* context;
};

Event::Event() : system(nullptr) {
}

Event::Event(System& system) : system(&system), first(nullptr), state(false) {
}

Event::Event(Event&& other) : system(other.system) {
if (other.system != nullptr) {
first = other.first;
if (other.first != nullptr) {
last = other.last;
}

state = other.state;
other.system = nullptr;
}
}

Event::~Event() {
assert(first == nullptr);
}

Event& Event::operator=(Event&& other) {
assert(first == nullptr);
system = other.system;
if (other.system != nullptr) {
first = other.first;
if (other.first != nullptr) {
last = other.last;
}

state = other.state;
other.system = nullptr;
}

return *this;
}

bool Event::get() const {
assert(system != nullptr);
return state;
}

void Event::clear() {
assert(system != nullptr);
state = false;
}

void Event::set() {
assert(system != nullptr);
state = true;
for (Waiter* waiter = first; waiter != nullptr; waiter = waiter->next) {
system->pushContext(waiter->context);
}

first = nullptr;
}

void Event::wait() {
assert(system != nullptr);
Waiter waiter = {nullptr, system->getCurrentContext()};
if (first != nullptr) {
last->next = &waiter;
} else {
first = &waiter;
}

last = &waiter;
while (!state) {
system->yield();
}
}
43 changes: 43 additions & 0 deletions src/System/Event.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
//
// This file is part of Bytecoin.
//
// Bytecoin 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 3 of the License, or
// (at your option) any later version.
//
// Bytecoin 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 Bytecoin. If not, see <http://www.gnu.org/licenses/>.

#pragma once

class System;

class Event {
public:
Event();
explicit Event(System& system);
Event(const Event&) = delete;
Event(Event&& other);
~Event();
Event& operator=(const Event&) = delete;
Event& operator=(Event&& other);
bool get() const;
void clear();
void set();
void wait();

private:
struct Waiter;

System* system;
Waiter* first;
Waiter* last;
bool state;
};
133 changes: 133 additions & 0 deletions src/System/System.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
//
// This file is part of Bytecoin.
//
// Bytecoin 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 3 of the License, or
// (at your option) any later version.
//
// Bytecoin 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 Bytecoin. If not, see <http://www.gnu.org/licenses/>.

#include "System.h"
#include <iostream>
#include <boost/asio/spawn.hpp>
#include <boost/context/fcontext.hpp>

namespace {
void contextProcedureStatic(intptr_t context) {
reinterpret_cast<System*>(context)->contextProcedure();
}
}

System::System() {
ioService = new boost::asio::io_service;
work = new boost::asio::io_service::work(*static_cast<boost::asio::io_service*>(ioService));
currentContext = new boost::context::fcontext_t;
}

System::~System() {
assert(procedures.empty());
assert(resumingContexts.empty());
while (!contexts.empty()) {

delete static_cast<boost::context::fcontext_t*>(contexts.top());

contexts.pop();
}
delete static_cast<boost::asio::io_service::work*>(work);
if (!static_cast<boost::asio::io_service*>(ioService)->stopped()) {
static_cast<boost::asio::io_service*>(ioService)->stop();
}
delete static_cast<boost::asio::io_service*>(ioService);
}

void* System::getCurrentContext() const {

return currentContext;
}

void* System::getIoService() {
return ioService;
}

void System::pushContext(void* context) {
resumingContexts.push(context);
}

void System::spawn(std::function<void()>&& procedure) {
procedures.emplace(std::move(procedure));
}

void System::wake() {
static_cast<boost::asio::io_service*>(ioService)->post([] {});
}

void System::yield() {
if (procedures.empty()) {
void* context;
for (;;) {
if (resumingContexts.empty()) {
boost::system::error_code errorCode;
static_cast<boost::asio::io_service*>(ioService)->run_one(errorCode);
if (errorCode) {
std::cerr << "boost::asio::io_service::run_onw failed, result=" << errorCode << '.' << std::endl;
throw std::runtime_error("System::yield");
}
} else {
context = resumingContexts.front();
resumingContexts.pop();
break;
}
}

if (context != currentContext) {
boost::context::fcontext_t* oldContext = static_cast<boost::context::fcontext_t*>(currentContext);
currentContext = context;
#if (BOOST_VERSION >= 105600)
boost::context::jump_fcontext(oldContext, *static_cast<boost::context::fcontext_t*>(context), reinterpret_cast<intptr_t>(this), false);
#else
boost::context::jump_fcontext(oldContext, static_cast<boost::context::fcontext_t*>(context), reinterpret_cast<intptr_t>(this), false);
#endif
}
} else {
void* context;
if (contexts.empty()) {
#if (BOOST_VERSION >= 105600)
context = new boost::context::fcontext_t(boost::context::make_fcontext(new uint8_t[65536] + 65536, 65536, contextProcedureStatic));
#else
context = new boost::context::fcontext_t(*boost::context::make_fcontext(new uint8_t[65536] + 65536, 65536, contextProcedureStatic));
#endif
} else {
context = contexts.top();
contexts.pop();
}


boost::context::fcontext_t* oldContext = static_cast<boost::context::fcontext_t*>(currentContext);
currentContext = context;
#if (BOOST_VERSION >= 105600)
boost::context::jump_fcontext(oldContext, *static_cast<boost::context::fcontext_t*>(context), reinterpret_cast<intptr_t>(this), false);
#else
boost::context::jump_fcontext(oldContext, static_cast<boost::context::fcontext_t*>(context), reinterpret_cast<intptr_t>(this), false);
#endif
}
}

void System::contextProcedure() {
void* context = currentContext;
for (;;) {
assert(!procedures.empty());
std::function<void()> procedure = std::move(procedures.front());
procedures.pop();
procedure();
contexts.push(context);
yield();
}
}
46 changes: 46 additions & 0 deletions src/System/System.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
//
// This file is part of Bytecoin.
//
// Bytecoin 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 3 of the License, or
// (at your option) any later version.
//
// Bytecoin 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 Bytecoin. If not, see <http://www.gnu.org/licenses/>.

#pragma once

#include <functional>
#include <queue>
#include <stack>

class System {
public:
System();
System(const System&) = delete;
~System();
System& operator=(const System&) = delete;
void* getCurrentContext() const;
void* getIoService();
void pushContext(void* context);
void spawn(std::function<void()>&& procedure);
void yield();
void wake();

void contextProcedure();

private:
void* ioService;
void* work;
std::stack<void*> contexts;
std::queue<std::function<void()>> procedures;
std::queue<void*> resumingContexts;
void* currentContext;
};
Loading

0 comments on commit 6d74194

Please sign in to comment.