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")
|
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")
|
||||||
elseif (${CMAKE_VERSION} STREQUAL "4.0.2")
|
elseif (${CMAKE_VERSION} STREQUAL "4.0.2")
|
||||||
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457")
|
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 ()
|
else ()
|
||||||
message(FATAL_ERROR "Can't enable CMAKE_EXPERIMENTAL_CXX_IMPORT_STD for this version of cmake, please edit top-lvl CMakeLists.txt")
|
message(FATAL_ERROR "Can't enable CMAKE_EXPERIMENTAL_CXX_IMPORT_STD for this version of cmake, please edit top-lvl CMakeLists.txt")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(networks_1 LANGUAGES CXX)
|
project(networks_1 LANGUAGES CXX)
|
||||||
|
|
||||||
|
|
||||||
set(CMP0155 NEW)
|
set(CMP0155 NEW)
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
|
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
|
||||||
@ -27,3 +30,5 @@ add_subdirectory(programs/lab4)
|
|||||||
|
|
||||||
add_executable(main main.cpp)
|
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
|
FILE_SET cxx_modules TYPE CXX_MODULES FILES
|
||||||
./src/exception.cppm
|
./src/exception.cppm
|
||||||
./src/windows.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;
|
module;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
# include "platform/windows.hpp"
|
# include "platform/windows.hpp"
|
||||||
@ -10,6 +9,14 @@ export module ru.landgrafhomyak.BGTU.networks_1.sockets;
|
|||||||
|
|
||||||
# include "platform/windows.cpp.inc"
|
# 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
|
#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/thread_routine.cppm
|
||||||
src/highlevel_impl.cppm
|
src/highlevel_impl.cppm
|
||||||
src/platform/windows.cppm
|
src/platform/windows.cppm
|
||||||
|
src/platform/posix.cppm
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(threads PRIVATE exceptions Synchronization)
|
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