blob: 1aec18b90d25432477b1fe7039d62fcda65c8f8d [file] [log] [blame]
// 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