From 55c2f3a79b70a70410f9d1938ab07a24b0cf064f Mon Sep 17 00:00:00 2001 From: Florian Fischer <florian.fl.fischer@fau.de> Date: Fri, 5 Feb 2021 12:44:16 +0100 Subject: [PATCH] add callback based fsearch implementation --- apps/fsearch/fsearch_callback.cpp | 127 ++++++++++++++++++++++++++++++ apps/fsearch/meson.build | 6 ++ 2 files changed, 133 insertions(+) create mode 100644 apps/fsearch/fsearch_callback.cpp diff --git a/apps/fsearch/fsearch_callback.cpp b/apps/fsearch/fsearch_callback.cpp new file mode 100644 index 00000000..b5961cf5 --- /dev/null +++ b/apps/fsearch/fsearch_callback.cpp @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2021 Florian Fischer +#include <fcntl.h> + +#include <array> +#include <cassert> +#include <cerrno> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <filesystem> +#include <iostream> +#include <string> +#include <utility> + +#include "Common.hpp" +#include "CountingPrivateSemaphore.hpp" +#include "Fiber.hpp" +#include "Runtime.hpp" +#include "emper.hpp" +#include "io.hpp" +#include "io/Future.hpp" + +namespace fs = std::filesystem; + +using emper::io::OpenatFuture; +using emper::io::ReadFuture; + +const size_t EMPER_RIPGREP_BUFSIZE = 4096; + +const char* needle; +size_t needle_len; + +class FileSearcher { + std::string path; + int fd = -1; + std::array<char, EMPER_RIPGREP_BUFSIZE> buf; + CPS& finished; + + public: + FileSearcher(std::string path, CPS& finished) : path(std::move(path)), finished(finished) {} + ~FileSearcher() { + if (fd > 0) { + emper::io::closeAndForget(fd); + fd = -1; + } + + finished.signalAndExit(); + } + + void kickoffSearch() { + OpenatFuture f(AT_FDCWD, path.c_str(), O_RDONLY); + f.setCallback([this](int32_t fd) { + if (fd < 0) { + errno = -fd; + DIE_MSG_ERRNO("open failed"); + } + + this->fd = fd; + submitRead(); + }); + + f.submit(); + } + + void onRead(int32_t bytes_read) { + if (bytes_read <= 0) { + // file was fully searched + if (bytes_read == 0) { + delete this; + return; + } + + errno = -bytes_read; + DIE_MSG_ERRNO("read failed"); + } + + if (memmem(&buf[0], bytes_read, needle, needle_len)) { + printf("%s\n", path.c_str()); + delete this; + return; + } + + submitRead(); + } + + void submitRead() { + assert(fd > 0); + ReadFuture f(fd, buf.data(), EMPER_RIPGREP_BUFSIZE, -1); + f.setCallback([this](int32_t bytes_read) { this->onRead(bytes_read); }); + f.submit(); + } +}; + +void walk_dir() { + CPS cps; + for (const auto& p : fs::recursive_directory_iterator(".")) { + if (!p.is_regular_file()) { + continue; + } + + cps.incrementCounterByOne(); + auto* searcher = new FileSearcher(p.path(), cps); + async([searcher] { searcher->kickoffSearch(); }); + } + + cps.wait(); + exit(EXIT_SUCCESS); +} + +auto main(int argc, char* argv[]) -> int { + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " <needle>" << std::endl; + return EXIT_FAILURE; + } + + needle = argv[1]; + needle_len = strlen(needle); + + Runtime runtime; + + auto* dirWalker = Fiber::from(walk_dir); + runtime.scheduleFromAnywhere(*dirWalker); + + runtime.waitUntilFinished(); +} diff --git a/apps/fsearch/meson.build b/apps/fsearch/meson.build index b5b548e0..9dc41f5c 100644 --- a/apps/fsearch/meson.build +++ b/apps/fsearch/meson.build @@ -3,3 +3,9 @@ fsearch_exe = executable( 'fsearch.cpp', dependencies: emper_dep, ) + +fsearch_callback_exe = executable( + 'fsearch_callback', + 'fsearch_callback.cpp', + dependencies: emper_dep, +) -- GitLab