Port to linux (not tested because linux compilers sucks)
This commit is contained in:
parent
e1e10a92f6
commit
ca1cedae85
@ -5,12 +5,15 @@ if (${CMAKE_VERSION} STREQUAL "4.1.1")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")
|
||||
elseif (${CMAKE_VERSION} STREQUAL "4.0.2")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457")
|
||||
elseif (${CMAKE_VERSION} STREQUAL "4.2.0-rc2")
|
||||
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")
|
||||
else ()
|
||||
message(FATAL_ERROR "Can't enable CMAKE_EXPERIMENTAL_CXX_IMPORT_STD for this version of cmake, please edit top-lvl CMakeLists.txt")
|
||||
endif()
|
||||
|
||||
project(networks_1 LANGUAGES CXX)
|
||||
|
||||
|
||||
set(CMP0155 NEW)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
|
||||
@ -26,4 +29,6 @@ add_subdirectory(modules/asyncio)
|
||||
add_subdirectory(programs/lab4)
|
||||
|
||||
add_executable(main main.cpp)
|
||||
target_link_libraries(main PRIVATE exceptions threads sockets streams)
|
||||
target_link_libraries(main PRIVATE exceptions threads sockets streams)
|
||||
|
||||
add_executable(test-gcc gcc2.cpp)
|
||||
|
||||
13
linux-gcc.dockerfile
Normal file
13
linux-gcc.dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk update \
|
||||
&& apk upgrade \
|
||||
&& apk add gcompat ninja-build linux-headers \
|
||||
&& apk --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main add gcc g++ gdb \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
RUN cd /root/ \
|
||||
&& wget https://github.com/Kitware/CMake/releases/download/v4.2.0-rc2/cmake-4.2.0-rc2-linux-x86_64.sh \
|
||||
&& sh cmake-4.2.0-rc2-linux-x86_64.sh --prefix=/opt/cmake --skip-license --include-subdir \
|
||||
&& rm cmake-4.2.0-rc2-linux-x86_64.sh \
|
||||
&& ln -s /opt/cmake/cmake-4.2.0-rc2-linux-x86_64/bin/cmake /usr/bin/cmake
|
||||
@ -7,4 +7,5 @@ target_sources(
|
||||
FILE_SET cxx_modules TYPE CXX_MODULES FILES
|
||||
./src/exception.cppm
|
||||
./src/windows.cppm
|
||||
./src/posix.cppm
|
||||
)
|
||||
61
modules/exceptions/src/posix.cppm
Normal file
61
modules/exceptions/src/posix.cppm
Normal file
@ -0,0 +1,61 @@
|
||||
module;
|
||||
|
||||
#ifdef __linux__
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#endif
|
||||
|
||||
|
||||
export module ru.landgrafhomyak.BGTU.networks_1.exceptions.posix;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
// import std;
|
||||
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
|
||||
|
||||
namespace LdH {
|
||||
export
|
||||
[[noreturn]]
|
||||
void throwFromLinuxErrCode(int code);
|
||||
|
||||
export
|
||||
[[noreturn]]
|
||||
void throwFromLastLinuxErr();
|
||||
|
||||
export void throwFromLastLinuxErrOrTimeout();
|
||||
}
|
||||
|
||||
module : private;
|
||||
|
||||
[[noreturn]]
|
||||
void LdH::throwFromLinuxErrCode(int code) {
|
||||
char msg[1024];
|
||||
// todo err check
|
||||
strerror_r(code, msg, 1024);
|
||||
size_t trim_size = std::strlen(msg);
|
||||
while (trim_size > 0) {
|
||||
switch (msg[--trim_size]) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
msg[trim_size] = '\0';
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]]
|
||||
void LdH::throwFromLastLinuxErr() {
|
||||
LdH::throwFromLinuxErrCode(errno);
|
||||
}
|
||||
|
||||
void LdH::throwFromLastLinuxErrOrTimeout() {
|
||||
int err = errno;
|
||||
if (err == ETIMEDOUT)
|
||||
return;
|
||||
LdH::throwFromLinuxErrCode(err);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,7 +1,6 @@
|
||||
module;
|
||||
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
# include "platform/windows.hpp"
|
||||
@ -10,6 +9,14 @@ export module ru.landgrafhomyak.BGTU.networks_1.sockets;
|
||||
|
||||
# include "platform/windows.cpp.inc"
|
||||
|
||||
#elif defined(__linux__)
|
||||
|
||||
# include "platform/linux.hpp"
|
||||
|
||||
export module ru.landgrafhomyak.BGTU.networks_1.sockets;
|
||||
|
||||
# include "platform/linux.cpp.inc"
|
||||
|
||||
#endif
|
||||
|
||||
module:private;
|
||||
module:private;
|
||||
|
||||
221
modules/sockets/src/platform/linux.cpp.inc
Normal file
221
modules/sockets/src/platform/linux.cpp.inc
Normal file
@ -0,0 +1,221 @@
|
||||
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
|
||||
import ru.landgrafhomyak.BGTU.networks_1.exceptions.posix;
|
||||
import ru.landgrafhomyak.BGTU.networks_1.streams;
|
||||
import :berkeley;
|
||||
|
||||
namespace LdH::Sockets {
|
||||
export
|
||||
void init_sockets() {
|
||||
}
|
||||
|
||||
export
|
||||
void deinit_sockets() {
|
||||
}
|
||||
|
||||
|
||||
struct _PosixSockContext {
|
||||
class address_t {
|
||||
public:
|
||||
sockaddr_storage _value;
|
||||
|
||||
private:
|
||||
address_t(sockaddr_storage value) : _value{value} {
|
||||
}
|
||||
|
||||
public:
|
||||
address_t() = default;
|
||||
|
||||
address_t(address_t const &) = default;
|
||||
|
||||
address_t(address_t &&) = default;
|
||||
|
||||
address_t &operator=(address_t const &) = default;
|
||||
|
||||
address_t &operator=(address_t &&) = default;
|
||||
|
||||
static address_t parse(char const *addr, char const *service) {
|
||||
addrinfo *p;
|
||||
int ret = getaddrinfo(addr, service, nullptr, &p);
|
||||
if (0 != ret) {
|
||||
LdH::throwFromLinuxErrCode(ret);
|
||||
}
|
||||
sockaddr_storage out;
|
||||
memset(&out, 0, sizeof(sockaddr_storage));
|
||||
memcpy(&out, p->ai_addr, p->ai_addrlen);
|
||||
freeaddrinfo(p);
|
||||
return address_t{out};
|
||||
}
|
||||
|
||||
std::string to_string() {
|
||||
char buffer[1024];
|
||||
if (nullptr != inet_ntop(this->_value.ss_family, &(this->_value), buffer, sizeof(sockaddr_storage))) {
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
|
||||
return std::string{buffer};
|
||||
}
|
||||
};
|
||||
|
||||
using sock_type_t = int;
|
||||
using proto_t = int;
|
||||
|
||||
struct af {
|
||||
public:
|
||||
static int inet() { return AF_INET; }
|
||||
static int inet6() { return AF_INET6; }
|
||||
static int ipx() { return AF_IPX; }
|
||||
};
|
||||
|
||||
struct sock_type {
|
||||
public:
|
||||
static int stream() { return SOCK_STREAM; }
|
||||
static int dgram() { return SOCK_DGRAM; }
|
||||
};
|
||||
|
||||
struct proto {
|
||||
public:
|
||||
static int tcp() { return IPPROTO_TCP; }
|
||||
static int udp() { return IPPROTO_UDP; }
|
||||
static int icmp() { return IPPROTO_ICMP; }
|
||||
};
|
||||
|
||||
class socket_t {
|
||||
private:
|
||||
int _value;
|
||||
|
||||
explicit socket_t(int value) : _value{value} {
|
||||
}
|
||||
|
||||
public:
|
||||
socket_t() : _value{-1} {
|
||||
}
|
||||
|
||||
socket_t(socket_t &&other) noexcept : _value{other._value} {
|
||||
other._value = -1;
|
||||
}
|
||||
|
||||
socket_t &operator=(socket_t &&other) noexcept {
|
||||
this->_value = other._value;
|
||||
other._value = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~socket_t() = default;
|
||||
|
||||
static socket_t create(address_t const &addr, int type, int proto) {
|
||||
int sock = ::socket(addr._value.ss_family, type, proto);
|
||||
if (sock == -1) {
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
|
||||
return socket_t{sock};
|
||||
}
|
||||
|
||||
void close() {
|
||||
if (0 != ::close(this->_value)) {
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
this->_value = -1;
|
||||
}
|
||||
|
||||
void connect(address_t addr) {
|
||||
if (0 != ::connect(this->_value, reinterpret_cast<sockaddr *>(&(addr._value)), sizeof(sockaddr)))
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
|
||||
void bind(address_t addr) {
|
||||
if (0 != ::bind(this->_value, reinterpret_cast<sockaddr *>(&(addr._value)), sizeof(sockaddr)))
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
|
||||
socket_t accept(address_t *addr) {
|
||||
int sock = ::accept(this->_value, reinterpret_cast<sockaddr *>(&(addr->_value)), nullptr);
|
||||
if (sock == -1) {
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
return socket_t{sock};
|
||||
}
|
||||
|
||||
void listen(std::size_t queue_size) {
|
||||
if (0 != ::listen(this->_value, queue_size)) {
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_stream(std::size_t size, char const *data) {
|
||||
while (true) {
|
||||
std::size_t sent_count = ::send(this->_value, data, size, 0);
|
||||
if (sent_count == -1) {
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
data += sent_count;
|
||||
size -= sent_count;
|
||||
if (size <= 0) return;
|
||||
}
|
||||
}
|
||||
|
||||
void recv_stream(std::size_t size, char *data) {
|
||||
while (true) {
|
||||
std::size_t sent_count = ::recv(this->_value, data, size, 0);
|
||||
if (sent_count == -1) {
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
data += sent_count;
|
||||
size -= sent_count;
|
||||
if (size <= 0) return;
|
||||
}
|
||||
}
|
||||
|
||||
void send_datagram(address_t dest, std::size_t size, char const *data) {
|
||||
int sent_count = ::sendto(this->_value, data, size, 0, reinterpret_cast<sockaddr *>(&dest._value), sizeof(dest._value));
|
||||
if (sent_count == -1) {
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
}
|
||||
|
||||
address_t recv_datagram(std::size_t size, char *data) {
|
||||
address_t out;
|
||||
socklen_t out_size = sizeof(out);
|
||||
int sent_count = ::recvfrom(this->_value, data, size, 0, reinterpret_cast<sockaddr *>(&out), &out_size);
|
||||
if (sent_count == -1) {
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(Berkeley::BerkeleySocketsContext<_PosixSockContext>);
|
||||
|
||||
|
||||
export using Address = Berkeley::Address<_PosixSockContext>;
|
||||
|
||||
export using StreamSocket = Berkeley::StreamSocket<_PosixSockContext>;
|
||||
|
||||
export using StreamSocketsServer = Berkeley::StreamSocketsServer<_PosixSockContext>;
|
||||
|
||||
export
|
||||
StreamSocket connect_tcp(Address addr) {
|
||||
return Berkeley::connect_tcp<_PosixSockContext>(addr);
|
||||
}
|
||||
|
||||
export
|
||||
StreamSocketsServer listen_tcp(Address addr, std::size_t queue_size) {
|
||||
return Berkeley::listen_tcp<_PosixSockContext>(addr, queue_size);
|
||||
}
|
||||
|
||||
export using ClientDatagramSocket = Berkeley::ClientDatagramSocket<_PosixSockContext>;
|
||||
|
||||
export using ServerDatagramSocket = Berkeley::ServerDatagramSocket<_PosixSockContext>;
|
||||
|
||||
export
|
||||
ClientDatagramSocket connect_udp(Address addr) {
|
||||
return Berkeley::connect_udp<_PosixSockContext>(addr);
|
||||
}
|
||||
|
||||
export
|
||||
ServerDatagramSocket listen_udp(Address addr) {
|
||||
return Berkeley::listen_udp<_PosixSockContext>(addr);
|
||||
}
|
||||
}
|
||||
8
modules/sockets/src/platform/linux.hpp
Normal file
8
modules/sockets/src/platform/linux.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <bits/stdc++.h>
|
||||
|
||||
@ -9,6 +9,7 @@ target_sources(
|
||||
src/thread_routine.cppm
|
||||
src/highlevel_impl.cppm
|
||||
src/platform/windows.cppm
|
||||
src/platform/posix.cppm
|
||||
)
|
||||
|
||||
target_link_libraries(threads PRIVATE exceptions Synchronization)
|
||||
111
modules/threads/src/platform/posix.cppm
Normal file
111
modules/threads/src/platform/posix.cppm
Normal file
@ -0,0 +1,111 @@
|
||||
module;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <linux/futex.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <bits/stdc++.h>
|
||||
|
||||
#endif
|
||||
|
||||
export module ru.landgrafhomyak.BGTU.networks_1.threads:impl.posix;
|
||||
|
||||
#ifdef __linux__
|
||||
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
|
||||
import ru.landgrafhomyak.BGTU.networks_1.exceptions.posix;
|
||||
import :thread_routine;
|
||||
import :highlevel_impl;
|
||||
|
||||
|
||||
namespace LdH {
|
||||
class NativeThreadWrapperForPosix {
|
||||
private:
|
||||
pthread_t _thread;
|
||||
|
||||
public:
|
||||
NativeThreadWrapperForPosix() : _thread{} {
|
||||
}
|
||||
|
||||
void join() {
|
||||
auto ret = pthread_join(this->_thread, nullptr);
|
||||
if (ret != 0) {
|
||||
LdH::throwFromLinuxErrCode(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
auto ret = pthread_join(this->_thread, nullptr);
|
||||
if (ret != 0) {
|
||||
LdH::throwFromLinuxErrCode(ret);
|
||||
}
|
||||
}
|
||||
|
||||
~NativeThreadWrapperForPosix() = default;
|
||||
|
||||
class notifier_t {
|
||||
std::uint32_t _ptr;
|
||||
|
||||
public:
|
||||
notifier_t() : _ptr{0} {
|
||||
}
|
||||
|
||||
void wait() {
|
||||
long ret = syscall(SYS_futex, &(this->_ptr), FUTEX_WAIT, 0, nullptr);
|
||||
if (ret == -1) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
return;
|
||||
default:
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void notify() {
|
||||
long ret = syscall(SYS_futex, &(this->_ptr), FUTEX_WAIT, INT_MAX);
|
||||
if (ret == -1) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
return;
|
||||
default:
|
||||
LdH::throwFromLastLinuxErr();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using kernel_ret_t = void *;
|
||||
|
||||
static void *kernel_ret() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit NativeThreadWrapperForPosix(pthread_t hThread) : _thread{hThread} {
|
||||
}
|
||||
|
||||
public:
|
||||
static NativeThreadWrapperForPosix start(std::string &, void * (*kernel)(void *), void *kernel_arg) {
|
||||
pthread_t native_thread;
|
||||
int ret = pthread_create(&native_thread, nullptr, kernel, kernel_arg);
|
||||
if (ret != 0) {
|
||||
LdH::throwFromLinuxErrCode(ret);
|
||||
}
|
||||
return NativeThreadWrapperForPosix{native_thread};
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(LdH::NativeHighLevelThreadWrapper<NativeThreadWrapperForPosix>);
|
||||
|
||||
export
|
||||
using ThreadController = LdH::CommonHighLevelThreadWrapper<NativeThreadWrapperForPosix>;
|
||||
|
||||
export ThreadController fork(std::string &&name, ThreadRoutine auto &&routine) {
|
||||
return _common_highlevel_fork<NativeThreadWrapperForPosix>(std::move(name), std::move(routine));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user