Browse Source

shared_fd base done, coverage 100%

devel
Ludovic 'Archivist' Lagouardette 4 years ago
parent
commit
5c5162dabe
6 changed files with 251 additions and 6 deletions
  1. +1
    -0
      .gitignore
  2. +17
    -0
      .vscode/launch.json
  3. +2
    -2
      Makefile
  4. +106
    -4
      include/shared_fd.hpp
  5. +1
    -0
      tests.cpp
  6. +124
    -0
      tests/shared_fd.cpp

+ 1
- 0
.gitignore View File

@ -36,3 +36,4 @@ bin/tests
default.profraw
bin/tests.profdata
bin/tests.profraw
bin/test_n

+ 17
- 0
.vscode/launch.json View File

@ -0,0 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "gdb",
"request": "launch",
"target": "./bin/tests",
"cwd": "${workspaceRoot}",
"valuesFormatting": "parseText",
"env": {"LLVM_PROFILE_FILE":"./bin/tests.profraw"}
}
]
}

+ 2
- 2
Makefile View File

@ -1,5 +1,5 @@
CXX= clang++-8
CXXFLAGS= --std=c++17 -fprofile-instr-generate -fcoverage-mapping
CXXFLAGS= --std=c++17 -g -fprofile-instr-generate -fcoverage-mapping
all: tests
@ -7,7 +7,7 @@ tests: bin/tests
LLVM_PROFILE_FILE="./bin/tests.profraw" ./bin/tests
@llvm-profdata merge -sparse ./bin/tests.profraw -o ./bin/tests.profdata
@llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata $(wildcard ./tests/*.cpp) include/*.hpp
@llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata $(wildcard ./tests/*.cpp) include/*.hpp | tail -n 1 | tr -s "\t" | awk '{print "$8" }'
@llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata ./tests/*.cpp include/*.hpp | tail -n 1 | tr -s " " | sed -e 's/ /,/g' -- | awk -F "," '{print $$9}' | sed -e 's/^/Untested lines: /g'
bin/tests: tests.cpp $(wildcard tests/*.cpp) ./tests/test_scaffold.h
@mkdir -p $(@D)

+ 106
- 4
include/shared_fd.hpp View File

@ -4,6 +4,8 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <string>
#include <atomic>
#include <cassert>
namespace gp{
using open_opt_flags = int;
@ -18,6 +20,8 @@ namespace gp{
exclusive = O_EXCL,
no_access_time = O_NOATIME,
no_follow = O_NOFOLLOW,
read = O_RDONLY,
write = O_WRONLY,
#ifdef O_TEMP
temporary = O_TEMP,
#endif
@ -44,13 +48,111 @@ namespace gp{
};
class shared_fd {
const int fd;
int fd;
std::atomic_int* guard;
int last_error;
shared_fd(int fd_v)
: fd(fd_v) {}
: fd(fd_v)
, guard(new std::atomic_int{1})
, last_error(0)
{}
public:
static shared_fd open(const std::string& filename, const open_opt_flags& flags) {
shared_fd()
: fd(-1)
, guard(nullptr)
, last_error(0)
{}
shared_fd(shared_fd& oth)
: fd(oth.fd)
, guard(oth.guard)
, last_error(0)
{
if(guard)
guard->fetch_add(1, std::memory_order_acq_rel);
}
shared_fd(shared_fd&& oth)
: last_error(0)
{
fd=oth.fd;
guard=oth.guard;
oth.fd=-1;
oth.guard=nullptr;
}
void operator=(shared_fd& oth)
{
this->~shared_fd();
fd = oth.fd;
guard = oth.guard;
if(guard)
guard->fetch_add(1, std::memory_order_acq_rel);
}
void operator=(shared_fd&& oth)
{
std::swap(fd,oth.fd);
std::swap(guard,oth.guard);
}
static shared_fd open(const std::string& filename, const open_opt_flags& flags, const open_opt_mode& mode = 0)
{
shared_fd ret{::open(filename.c_str(), flags, mode)};
return ret;
}
static shared_fd create(const std::string& filename, const open_opt_mode& mode)
{
shared_fd ret{::creat(filename.c_str(), mode)};
return ret;
}
bool is_valid() const {
return guard && (fd>=0);
}
bool has_failed() const {
return last_error;
}
std::string_view read(const std::string_view buffer)
{
int sz = ::read(fd, (void*)(buffer.begin()), buffer.size());
if(sz<0)
last_error = errno;
else
last_error = 0;
sz = sz<0?0:sz;
return std::string_view(buffer.begin(), sz);
}
std::string_view write(const std::string_view buffer)
{
int sz = ::write(fd, (void*)(buffer.begin()), buffer.size());
if(sz<0)
last_error = errno;
else
last_error = 0;
sz = sz<0?0:sz;
return std::string_view(buffer.begin()+sz, buffer.size()-sz);
}
~shared_fd()
{
if(guard)
if(guard->fetch_sub(1, std::memory_order_acq_rel) == 1)
{
assert(guard->load() == 0);
assert(fd >= 0);
delete guard;
guard = nullptr;
if(fd >= 0)
{
::close(fd);
}
}
}
};
}

+ 1
- 0
tests.cpp View File

@ -1,5 +1,6 @@
#include "test_scaffold.h"
#include "meta_test.cpp"
#include "shared_fd.cpp"
#include <iostream>
int main()

+ 124
- 0
tests/shared_fd.cpp View File

@ -0,0 +1,124 @@
#include "shared_fd.hpp"
#include "test_scaffold.h"
struct create_test : public test_scaffold {
create_test() {
name = __FILE__ ":1";
}
virtual int run() {
auto fd = gp::shared_fd::create("./bin/test_n", int(gp::open_modes::user_read) | int(gp::open_modes::user_write));
return fd.is_valid()?0:1;
}
};
append_test dummy_sdfhuisd3(new create_test{});
struct open_test : public test_scaffold {
open_test() {
name = __FILE__ ":2";
}
virtual int run() {
auto fd = gp::shared_fd::open("./bin/test_n", int(gp::open_options::append));
return fd.is_valid()?0:1;
}
};
append_test dummy_sdf564dd3(new open_test{});
struct manip_test : public test_scaffold {
manip_test() {
name = __FILE__ ":3";
}
virtual int run() {
auto fd = gp::shared_fd::open("./bin/test_n", int(gp::open_options::append));
int error = fd.is_valid()?0:1;
auto fd_cpy = fd;
error += fd_cpy.is_valid()?0:1;
gp::shared_fd constr_cpy(fd_cpy);
error += constr_cpy.is_valid()?0:1;
gp::shared_fd constr_mv(std::move(constr_cpy));
error += constr_mv.is_valid()?0:1;
gp::shared_fd assign_cpy;
assign_cpy.operator=(fd_cpy);
error += assign_cpy.is_valid()?0:1;
gp::shared_fd assign_mv;
assign_mv.operator=(std::move(assign_cpy));
error += assign_mv.is_valid()?0:1;
error += (!assign_cpy.is_valid())?0:1;
return error;
}
};
append_test dummy_lkjs64dd3(new manip_test{});
struct rw_test : public test_scaffold {
rw_test() {
name = __FILE__ ":4";
}
virtual int run() {
auto fd = gp::shared_fd::open("./bin/test_n", int(gp::open_options::write));
int error = fd.is_valid()?0:1;
fd.write("potatoes");
error += fd.has_failed();
fd = gp::shared_fd::open("./bin/test_n", int(gp::open_options::read));
std::array<char,8> buffer;
auto str = fd.read(std::string_view(buffer.begin(), buffer.size()));
error += fd.has_failed();
error += (str != "potatoes");
return error;
}
};
append_test dummy_l6z5e4rdd3(new rw_test{});
struct rw_err_test : public test_scaffold {
rw_err_test() {
name = __FILE__ ":5";
}
virtual int run() {
auto fd = gp::shared_fd::create("./bin/test_n", int(gp::open_modes::user_read) | int(gp::open_modes::user_write));
fd = gp::shared_fd::open("./bin/test_n", int(gp::open_options::read));
int error = fd.is_valid()?0:1;
fd.write("potatoes");
error += fd.has_failed();
fd = gp::shared_fd::open("./bin/test_n", int(gp::open_options::write));
error += fd.is_valid()?0:1;
std::array<char,8> buffer;
auto str = fd.read(std::string_view(buffer.begin(), buffer.size()));
error += fd.has_failed();
return error == 2 ? 0 : 1;
}
};
append_test dummy_l6987erd3(new rw_err_test{});

Loading…
Cancel
Save