Skip to content

Commit d4eb7e2

Browse files
committed
libpressio version 0.60.0
Major Changes + ABI break: the pressio_io_read and related experimental functions no longer delete or steal the input, but more correctly move the input as documented. Previously these functions deleted the input value, but this made it very difficult to safely wrap these functions on platforms that are garbage collected. + BREAKING: the `libpressio` higher-level python binding had several changes to how it handled configurations: 1. bytes objects are now created as pressio_data objects this is to be more conistent across the interface and fix some faulty conversions in SZ-ExaFEL that should have worked 2. mpi4py MPI Communicator objects can now be passed if built with mpi4py support 3. Several changes to how type-inference works in the python bindings. For most users, these will just be improvements, and enable a correct implementation of numcodecs.Codec interface + if a template object is NOT passed, we no longer set entires with a `None` value. This prevents segfaults + if a template object is passed, we now only pass the new options rather than all of the objects from the template. + if a template object is passed, we call pressio_options.set_type if a `None` value is passed with the type from the template. 4. Several default arguments were added to make things default construable. 5. `name` parameters are now only passed if they are truthy 6. get_configurations was renamed get_compile_config() to be more consistently and understandably named 7. get_config() now returns a dict which can be directly passed to `from_configuration` and things should just work 8. Similar changes were made to PressioIO + A pretty substantial rewrite to how external_forkexec reads from its child process to use `select` to be more efficient and avoid deadlocks in poorly behaved (segfaulting) child processes. Minor Changes + pressio_data::dimensions now returns a const reference + better debugging output in the external metric test cases Bug Fixes + fixed a case where the constructor to pressio_data would segfault if passed a nullptr + fixed a number of segfaults when using distributed_manager (i.e. many_indepenent/many_dependent/etc...) when building with C++11 caused by constructing with an empty initializer list instead of compat::nullopt + fixed a number of compilation failures in the JSON bindings that incorrectly were implemented in C++17. + pinned the version of gtest to avoid build failures in anticipation of them adding an abseil dependency.
1 parent a5e40c0 commit d4eb7e2

File tree

17 files changed

+206
-80
lines changed

17 files changed

+206
-80
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
2-
project(libpressio VERSION "0.59.0" LANGUAGES CXX C)
2+
project(libpressio VERSION "0.60.0" LANGUAGES CXX C)
33

44
#correct was to set a default build type
55
# https://blog.kitware.com/cmake-and-the-default-build-type/

include/libpressio_ext/cpp/data.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ struct pressio_data {
339339
/**
340340
* \returns a copy of the vector of dimensions
341341
*/
342-
std::vector<size_t> dimensions() const {
342+
std::vector<size_t> const& dimensions() const {
343343
return dims;
344344
}
345345

include/libpressio_ext/io/posix.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ extern "C" {
2424
* If dims is not null, The user SHOULD assume that the memory pointed to by this pointer has been "moved" in a C++11 sense and the user MUST not rely on its contents.
2525
* The implementation MAY return this pointer and reuse the underlying space if pressio_data_has_data(dims) returns true.
2626
* \param[in,out] in_file an file open for reading seeked to the beginning of the data to read in.
27-
* \returns a pointer to a (possibly new) pressio data structure.
27+
* \returns a pointer to a new pressio data structure.
2828
*
2929
*/
3030
struct pressio_data* pressio_io_data_fread(struct pressio_data* dims, FILE* in_file);
@@ -39,7 +39,7 @@ extern "C" {
3939
* If dims is not null, The user SHOULD assume that the memory pointed to by this pointer has been "moved" in a C++11 sense and the user MUST not rely on its contents.
4040
* The implementation MAY return this pointer and reuse the underlying space if pressio_data_has_data(ptr) returns true.
4141
* \param[in,out] in_filedes an file open for reading seeked to the beginning of the data to read in. If dims is not null, only pressio_data_get_bytes(dims) bytes are read.
42-
* \returns a pointer to a (possibly new) pressio data structure.
42+
* \returns a pointer to a new pressio data structure.
4343
*
4444
*/
4545
struct pressio_data* pressio_io_data_read(struct pressio_data* dims, int in_filedes);
@@ -53,7 +53,7 @@ extern "C" {
5353
* If dims is not null, The user SHOULD assume that the memory pointed to by this pointer has been "moved" in a C++11 sense and the user MUST not rely on its contents.
5454
* The implementation MAY return this pointer and reuse the underlying space if pressio_data_has_data(dims) returns true.
5555
* \param[in,out] out_file an file open for reading seeked to the beginning of the data to read in.
56-
* \returns a pointer to a (possibly new) pressio data structure.
56+
* \returns a pointer to a new pressio data structure.
5757
*
5858
*/
5959
struct pressio_data* pressio_io_data_path_read(struct pressio_data* dims, const char* out_file);

src/plugins/io/csv.cc

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,12 @@ namespace {
4646
struct csv_io : public libpressio_io_plugin
4747
{
4848
virtual struct pressio_data* read_impl(struct pressio_data* data) override {
49-
if(data != nullptr) pressio_data_free(data);
50-
5149
std::ifstream in{path};
5250
if(not in) {
5351
bad_path(path);
5452
return nullptr;
5553
}
56-
size_t sizes[2] = {0,0};
54+
std::array<size_t,2> sizes {0,0};
5755
std::vector<double> builder;
5856
for(std::string line; std::getline(in, line, line_delim.front()); sizes[0]++) {
5957
if(sizes[0] < skip_rows) continue;
@@ -65,12 +63,19 @@ struct csv_io : public libpressio_io_plugin
6563
sizes[1] = column;
6664
}
6765
sizes[0] -= skip_rows;
68-
return pressio_data_new_copy(
69-
pressio_double_dtype,
70-
builder.data(),
71-
2,
72-
sizes
73-
);
66+
if(data && data->has_data() && std::equal(sizes.begin(), sizes.end(), data->dimensions().begin(), data->dimensions().end()) && data->dtype() == pressio_double_dtype) {
67+
auto ret = pressio_data_new_empty(pressio_byte_dtype, 0, nullptr);
68+
*ret = std::move(*data);
69+
std::copy(builder.begin(), builder.end(), static_cast<double*>(ret->data()));
70+
return ret;
71+
} else {
72+
return pressio_data_new_copy(
73+
pressio_double_dtype,
74+
builder.data(),
75+
2,
76+
sizes.data()
77+
);
78+
}
7479
}
7580

7681
virtual int write_impl(struct pressio_data const* data) override{

src/plugins/io/hdf5.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ struct hdf5_io: public libpressio_io_plugin {
241241
if(buffer == nullptr) {
242242
ret = pressio_data_new_owning(*dtype, pressio_size.size(), pressio_size.data());
243243
} else {
244-
ret = buffer;
244+
ret = pressio_data_new_empty(pressio_byte_dtype, 0, nullptr);
245+
*ret = std::move(*buffer);
245246
}
246247
auto ptr = pressio_data_ptr(ret, nullptr);
247248
std::vector<hsize_t> memextents(std::begin(pressio_size), std::end(pressio_size));
@@ -297,7 +298,18 @@ struct hdf5_io: public libpressio_io_plugin {
297298
} else {
298299
char err_msg[1024];
299300
std::fill(err_msg, err_msg+1024, '\0');
300-
strerror_r(errno, err_msg, 1024);
301+
302+
// gnulibc insists on providing their implementation
303+
// of strerror_r when compiling with C++ which returns a char* which
304+
// is declared warn_unused. However, there is also a POSIX version
305+
// which returns a int. In either case, we can't really recover
306+
// from the error so capture the value in a variable and explicitly
307+
// cast to (void) to silence the warning. BAD GNU...
308+
//
309+
// The other versions are either not thread safe or GNU extensions
310+
auto rc = strerror_r(errno, err_msg, 1024);
311+
(void)rc;
312+
301313
set_error(1, err_msg);
302314
return 1;
303315
}

src/plugins/io/noop.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
#include "std_compat/memory.h"
1212

1313
struct noop_io : public libpressio_io_plugin {
14-
virtual struct pressio_data* read_impl(struct pressio_data* data) override {
15-
if(data != nullptr) pressio_data_free(data);
14+
virtual struct pressio_data* read_impl(struct pressio_data*) override {
1615
return nullptr;
1716
}
1817

src/plugins/io/petsc.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ struct petsc_io : public libpressio_io_plugin {
9191
if (data != nullptr && pressio_data_dtype(data) == pressio_dtype_from_type<PetscScalar>() &&
9292
pressio_data_num_dimensions(data) == 2 && pressio_data_get_dimension(data, 0) == sizes[0] &&
9393
pressio_data_get_dimension(data, 1) == sizes[1] && pressio_data_has_data(data)) {
94-
ret = data;
94+
ret = pressio_data_new_empty(pressio_byte_dtype, 0, nullptr);
95+
*ret = std::move(*data);
9596
PetscScalar *data_ptr = static_cast<PetscScalar *>(pressio_data_ptr(data, nullptr));
9697
std::copy(raw_data, raw_data + (rows * columns), data_ptr);
9798
} else {

src/plugins/io/posix.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ extern "C" {
2929
auto dims_v = dims->dimensions();
3030
ret = pressio_data_new_owning(dtype, dims_v.size(), dims_v.data());
3131
}
32-
pressio_data_free(dims);
3332
} else {
3433
struct stat statbuf;
3534
if(fstat(in_filedes, &statbuf)) {

src/plugins/launch/external_forkexec.cc

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <unistd.h>
55
#include <iterator>
66
#include <sys/wait.h>
7+
#include <errno.h>
78
#include "std_compat/memory.h"
89

910
struct external_forkexec: public libpressio_launch_plugin {
@@ -36,6 +37,7 @@ extern_proc_results launch(std::vector<std::string> const& full_command) const o
3637
case 0:
3738
//in the child process
3839
{
40+
close(STDIN_FILENO);
3941
close(stdout_pipe_fd[0]);
4042
close(stderr_pipe_fd[0]);
4143
dup2(stdout_pipe_fd[1], 1);
@@ -78,21 +80,72 @@ extern_proc_results launch(std::vector<std::string> const& full_command) const o
7880
char buffer[2048];
7981
std::ostringstream stdout_stream;
8082
std::ostringstream stderr_stream;
81-
do {
82-
//read the stdout[0]
83-
int nread;
84-
while((nread = read(stdout_pipe_fd[0], buffer, 2048)) > 0) {
85-
stdout_stream.write(buffer, nread);
83+
bool stdout_closed = false, stderr_closed = false;
84+
85+
while(true) {
86+
int ready, nfds = 0;
87+
ssize_t nread;
88+
fd_set readfds, writefds, exceptfds;
89+
90+
FD_ZERO(&readfds);
91+
FD_ZERO(&writefds);
92+
FD_ZERO(&exceptfds);
93+
if(not stdout_closed) {
94+
FD_SET(stdout_pipe_fd[0], &readfds);
95+
nfds = std::max(stdout_pipe_fd[0], nfds);
8696
}
87-
88-
//read the stderr[0]
89-
while((nread = read(stderr_pipe_fd[0], buffer, 2048)) > 0) {
90-
stderr_stream.write(buffer, nread);
97+
if(not stderr_closed) {
98+
FD_SET(stderr_pipe_fd[0], &readfds);
99+
nfds = std::max(stderr_pipe_fd[0], nfds);
91100
}
92101

93-
//wait for the child to complete
94-
waitpid(child, &status, 0);
95-
} while (not WIFEXITED(status));
102+
if(stdout_closed && stderr_closed) {
103+
break;
104+
}
105+
106+
ready = select(nfds+1, &readfds, &writefds, &exceptfds, nullptr);
107+
108+
if(ready == -1 && errno == EINTR) {
109+
continue;
110+
}
111+
112+
if(!stdout_closed && FD_ISSET(stdout_pipe_fd[0], &readfds)) {
113+
nread = read(stdout_pipe_fd[0], buffer, sizeof buffer);
114+
if(nread > 0) {
115+
stdout_stream.write(buffer, nread);
116+
} else if (nread == 0) {
117+
stdout_closed = true;
118+
}
119+
}
120+
121+
if(!stderr_closed && FD_ISSET(stderr_pipe_fd[0], &readfds)) {
122+
nread = read(stderr_pipe_fd[0], buffer, sizeof buffer);
123+
if(nread > 0) {
124+
stderr_stream.write(buffer, nread);
125+
} else if(nread == 0) {
126+
stderr_closed = true;
127+
}
128+
}
129+
}
130+
131+
waitpid(child, &status, 0);
132+
close(stdout_pipe_fd[0]);
133+
close(stderr_pipe_fd[0]);
134+
// do {
135+
// //read the stdout[0]
136+
// int nread;
137+
// while((nread = read(stdout_pipe_fd[0], buffer, 2048)) > 0) {
138+
// stdout_stream.write(buffer, nread);
139+
// }
140+
//
141+
// //read the stderr[0]
142+
// while((nread = read(stderr_pipe_fd[0], buffer, 2048)) > 0) {
143+
// stderr_stream.write(buffer, nread);
144+
// }
145+
//
146+
// //wait for the child to complete
147+
// waitpid(child, &status, 0);
148+
// } while (not WIFEXITED(status));
96149

97150
results.proc_stdout = stdout_stream.str();
98151
results.proc_stderr = stderr_stream.str();

src/pressio_distributed_manager.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ compat::optional<std::vector<size_t>> distributed_build_groups(const unsigned in
77
if(size <= 1) return std::vector<size_t>{0};
88

99
//if the user tries to allocate more processes than exist report an error
10-
if(size < (n_workers_groups + n_masters)) return {};
10+
if(size < (n_workers_groups + n_masters)) return compat::nullopt;
1111

1212
//if the user ties to allocate all processes as
13-
if(n_workers_groups == size || n_masters == size) return {};
13+
if(n_workers_groups == size || n_masters == size) return compat::nullopt;
1414

1515
//root must be a valid rank
16-
if(root >= size) return {};
16+
if(root >= size) return compat::nullopt;
1717

1818

1919
//the zero rank is guaranteed the code below to be a master prior to the swap below

0 commit comments

Comments
 (0)