<commit_before>// Copyright (C) 2018 <NAME> <<EMAIL>>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <primitives/file_monitor.h>

#include <primitives/thread.h>

namespace primitives
{

namespace detail
{

int uv_loop_close(uv_loop_t &loop, Strings &errors)
{
    int r;
    if (r = uv_loop_close(&loop); r)
    {
        if (r == UV_EBUSY)
        {
            auto wlk = [](uv_handle_t* handle, void* arg)
            {
                if (handle)
                    uv_close(handle, 0);
            };
            uv_walk(&loop, wlk, 0);
            while (uv_run(&loop, UV_RUN_DEFAULT) != 0)
                ;
            if (r = uv_loop_close(&loop); r)
            {
                if (r == UV_EBUSY)
                    errors.push_back("resources were not cleaned up: "s + uv_strerror(r));
                else
                    errors.push_back("uv_loop_close() error: "s + uv_strerror(r));
            }
        }
        else
            errors.push_back("uv_loop_close() error: "s + uv_strerror(r));
    }
    return r;
}

}

namespace filesystem
{

FileMonitor::record::record(FileMonitor *mon, const path &dir, Callback callback, bool recursive)
    : mon(mon), dir(dir), dir_holder(dir.u8string()), callback(callback)
{
    if (uv_fs_event_init(&mon->loop, &e))
        return;
    e.data = this;
    if (uv_fs_event_start(&e, cb, dir_holder.c_str(),
        // was 0 = non recursive
        recursive ? UV_FS_EVENT_RECURSIVE : 0
    ) < 0)
    {
        // maybe unconditionally?
        if (uv_is_active((uv_handle_t*)&e))
            uv_close((uv_handle_t*)&e, 0);
    }
}

FileMonitor::record::~record()
{
    if (uv_is_active((uv_handle_t*)&e))
        uv_close((uv_handle_t*)&e, 0);
}

void FileMonitor::record::stop()
{
    uv_fs_event_stop(&e);
}

void FileMonitor::record::cb(uv_fs_event_t* handle, const char* filename, int events, int status)
{
    auto r = (record*)handle->data;
    if (status < 0)
    {
        if (status == UV_EBADF)
            return;
        return r->stop();
    }
    if (!filename)
        return;
    auto fn = fs::u8path(filename);
    if (r->mon->has_file(r->dir, fn) && r->callback)
        r->callback(r->dir / fn);
}

FileMonitor::FileMonitor()
{
    uv_loop_init(&loop);
    uv_run(&loop, UV_RUN_ONCE); // why?
}

FileMonitor::~FileMonitor()
{
    stop();
}

void FileMonitor::stop()
{
    if (stopped)
        return;
    stopped = true;

    // first, stop all watchers, but not clear them!!!
    for (auto &d : dir_files)
        d.second.r->stop();

    // join thread
    uv_stop(&loop);

    Strings errors;
    // and cleanup loop
    ::primitives::detail::uv_loop_close(loop, errors);
    for (auto &e : errors)
        std::cerr << e << "\n";
}

void FileMonitor::run()
{
    uv_run(&loop, UV_RUN_DEFAULT);
}

void FileMonitor::addFile(const path &p, record::Callback cb, bool recursive)
{
    if (stopped)
        return;
    if (p.empty())
        return;
<commit_msg>Cleanup filemon loop in destructor.<commit_after>// Copyright (C) 2018 <NAME> <<EMAIL>>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <primitives/file_monitor.h>

#include <primitives/thread.h>

namespace primitives
{

namespace detail
{

int uv_loop_close(uv_loop_t &loop, Strings &errors)
{
    int r;
    if (r = uv_loop_close(&loop); r)
    {
        if (r == UV_EBUSY)
        {
            auto wlk = [](uv_handle_t* handle, void* arg)
            {
                if (handle)
                    uv_close(handle, 0);
            };
            uv_walk(&loop, wlk, 0);
            while (uv_run(&loop, UV_RUN_DEFAULT) != 0)
                ;
            if (r = uv_loop_close(&loop); r)
            {
                if (r == UV_EBUSY)
                    errors.push_back("resources were not cleaned up: "s + uv_strerror(r));
                else
                    errors.push_back("uv_loop_close() error: "s + uv_strerror(r));
            }
        }
        else
            errors.push_back("uv_loop_close() error: "s + uv_strerror(r));
    }
    return r;
}

}

namespace filesystem
{

FileMonitor::record::record(FileMonitor *mon, const path &dir, Callback callback, bool recursive)
    : mon(mon), dir(dir), dir_holder(dir.u8string()), callback(callback)
{
    if (uv_fs_event_init(&mon->loop, &e))
        return;
    e.data = this;
    if (uv_fs_event_start(&e, cb, dir_holder.c_str(),
        // was 0 = non recursive
        recursive ? UV_FS_EVENT_RECURSIVE : 0
    ) < 0)
    {
        // maybe unconditionally?
        if (uv_is_active((uv_handle_t*)&e))
            uv_close((uv_handle_t*)&e, 0);
    }
}

FileMonitor::record::~record()
{
    if (uv_is_active((uv_handle_t*)&e))
        uv_close((uv_handle_t*)&e, 0);
}

void FileMonitor::record::stop()
{
    uv_fs_event_stop(&e);
}

void FileMonitor::record::cb(uv_fs_event_t* handle, const char* filename, int events, int status)
{
    auto r = (record*)handle->data;
    if (status < 0)
    {
        if (status == UV_EBADF)
            return;
        return r->stop();
    }
    if (!filename)
        return;
    auto fn = fs::u8path(filename);
    if (r->mon->has_file(r->dir, fn) && r->callback)
        r->callback(r->dir / fn);
}

FileMonitor::FileMonitor()
{
    uv_loop_init(&loop);
    uv_run(&loop, UV_RUN_ONCE); // why?
}

FileMonitor::~FileMonitor()
{
    stop();

    Strings errors;
    // cleanup loop
    ::primitives::detail::uv_loop_close(loop, errors);
    for (auto &e : errors)
        std::cerr << e << "\n";
}

void FileMonitor::stop()
{
    if (stopped)
        return;
    stopped = true;

    // first, stop all watchers, but not clear them!!!
    for (auto &d : dir_files)
        d.second.r->stop();

    // stop loop
    uv_stop(&loop);
}

void FileMonitor::run()
{
    uv_run(&loop, UV_RUN_DEFAULT);
}

void FileMonitor::addFile(const path &p, record::Callback cb, bool recursive)
{
    if (stopped)
        return;
    if (p.empty())
        return;

{'fraction_non_alphanumeric': 0.1462672220442166, 'fraction_numerical': 0.006087792374239026, 'mean_word_length': 2.2634605331939364, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '234028', 'n_tokens_mistral': 2245, 'n_tokens_neox': 2140, 'n_words': 499}