| // Copyright (C) 2020 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| #include "dump_events_to_fd.h" |
| |
| #include "npy.h" |
| #include "npyiter.h" |
| #include "pybuffer.h" |
| #include "pyobj.h" |
| #include "pyparsetuple.h" |
| |
| namespace dctv { |
| |
| static |
| unique_pyref |
| dump_events_to_fd(PyObject*, PyObject* args) |
| { |
| PARSEPYARGS( |
| (pyref, events_mapping) |
| (pyref, offset_source) |
| (int, out_fd) |
| )(args); |
| |
| // TODO(dancol): respect the lint warning and add a cloexec FD dup. |
| int out_fd_dup = dup(out_fd); // NOLINT |
| if (out_fd_dup < 0) |
| throw_from_errno(); |
| FINALLY({if (out_fd_dup >= 0) close(out_fd_dup);}); |
| FILE* out_file = fdopen(out_fd_dup, "w"); |
| if (!out_file) |
| throw_from_errno(); |
| FINALLY(fclose(out_file)); |
| out_fd_dup = -1; // Ownership transferred to out_file |
| |
| PyBuffer py_buffer(events_mapping); |
| |
| assume(py_buffer->len >= 0); |
| size_t length = py_buffer->len; |
| if (py_buffer->itemsize != 1) |
| throw_pyerr_msg(PyExc_AssertionError, "weird buffer format"); |
| const char* const buffer = static_cast<const char*>(py_buffer->buf); |
| const char* const end = buffer + length; |
| |
| NpyIterConfig config; |
| config.casting = NPY_UNSAFE_CASTING; |
| config.iter_flags |= NPY_ITER_BUFFERED; |
| auto offit = NpyIteration1<uint64_t>( |
| as_any_pyarray(offset_source), config); |
| if (!offit.is_at_eof()) { |
| do { |
| const uint64_t raw_offset = offit.get(); |
| if (raw_offset > length) { |
| throw_pyerr_msg(PyExc_ValueError, "offset out of range"); |
| } |
| const size_t offset = static_cast<size_t>(raw_offset); |
| for (const char* c = buffer + offset; c < end && *c != '\n'; ++c) |
| if (putc_unlocked(*c, out_file) == EOF) |
| throw_from_errno(); |
| if (putc_unlocked('\n', out_file) == EOF) |
| throw_from_errno(); |
| } while (offit.advance()); |
| } |
| |
| if (fflush_unlocked(out_file)) |
| throw_from_errno(); |
| return addref(Py_None); |
| } |
| |
| |
| |
| static PyMethodDef functions[] = { |
| make_methoddef("dump_events_to_fd", |
| wraperr<dump_events_to_fd>(), |
| METH_VARARGS, |
| "Dump events from a mapped trace"), |
| { 0 } |
| }; |
| |
| void |
| init_dump_events_to_fd(pyref m) |
| { |
| register_functions(m, functions); |
| } |
| |
| } // namespace dctv |