From: Arkadiusz Pietraszek Date: Thu, 19 Apr 2018 08:38:07 +0000 (+0200) Subject: [Filesystem] Worker implementation for separate thread. X-Git-Tag: submit/tizen/20180518.121229~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7b27168e71782488f5cf509a5abf203cbdf894d8;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Filesystem] Worker implementation for separate thread. ACR: http://suprem.sec.samsung.net/jira/browse/TWDAPI-121 Change-Id: I3096a27d6684c1ee4c226aebd2076c9b6f73f23c Signed-off-by: Szymon Jastrzebski Signed-off-by: Arkadiusz Pietraszek Signed-off-by: Jakub Skowron Signed-off-by: Pawel Wasowski --- diff --git a/src/filesystem/filesystem_instance.cc b/src/filesystem/filesystem_instance.cc index 33d0673b..81c635c8 100644 --- a/src/filesystem/filesystem_instance.cc +++ b/src/filesystem/filesystem_instance.cc @@ -53,6 +53,81 @@ FileHandle::~FileHandle() { } } +void FilesystemInstance::Worker::main() { + std::unique_lock lck{jobs_mtx}; + while (true) { + jobs_cond.wait(lck, [this] { return !jobs.empty() || exit; }); + if (exit) { + return; + } + + while (!jobs.empty()) { + auto job = jobs.front(); + jobs.pop_front(); + //////////// end of critical section + lck.unlock(); + + try { + job.func(); + } catch (...) { + // should never happen + LoggerE("Func should never throw"); + } + + try { + job.finally(); + } catch (...) { + // should never happen + LoggerE("Finally should never throw"); + } + + lck.lock(); + //////////// start of critical section + if (exit) { + return; + } + } + } +} + +void FilesystemInstance::Worker::add_job(const std::function& func, + const std::function& finally) { + { + std::lock_guard lck{jobs_mtx}; + jobs.push_back({func, finally}); + } + jobs_cond.notify_one(); +} + +FilesystemInstance::Worker::Worker() + : exit(false), thread(std::bind(&FilesystemInstance::Worker::main, this)) { +} + +FilesystemInstance::Worker::~Worker() { + { + // use memory barrier for exit flag (could be std::atomic_flag, but we use lock instead) + std::lock_guard lck{jobs_mtx}; + exit = true; + } + jobs_cond.notify_one(); + + try { + thread.join(); + } catch (std::exception& e) { + LoggerE("Failed to join thread: %s", e.what()); + } + + // finalize jobs left in queue + for (auto job : jobs) { + try { + job.finally(); + } catch (...) { + // should never happen + LoggerE("Finally should never throw"); + } + } +}; + FilesystemInstance::FilesystemInstance() { ScopeLogger(); using std::placeholders::_1; diff --git a/src/filesystem/filesystem_instance.h b/src/filesystem/filesystem_instance.h index 3457b0e4..d5dc284e 100644 --- a/src/filesystem/filesystem_instance.h +++ b/src/filesystem/filesystem_instance.h @@ -62,6 +62,50 @@ class FilesystemInstance : public common::ParsedInstance, FilesystemStateChangeL private: FileHandleMap opened_files; + /** + * @brief Implements single worker executing in new thread + * + * Jobs are done in order. If this worker is destroyed all pending jobs are cancelled, + * and all remaining 'finally' functions are called. + */ + class Worker { + bool exit; + struct Job { + std::function func; + std::function finally; + }; + std::deque jobs; + std::thread thread; + std::mutex jobs_mtx; + std::condition_variable jobs_cond; + void main(void); + + public: + Worker(); + ~Worker(); + + /** + * @brief Schedule a job + * Parameters will be copied (no reference is held) + * + * @param job function called as a job (should not throw) + * @param finally function called after completion or canceling. (should not throw) + */ + void add_job(const std::function& job, const std::function& finally); + + /** + * @brief Schedule a job. Same as above, but with empty finally function. + * Parameter will be copied (no reference is held) + * + * @param job function called as a job (should not throw) + */ + void add_job(const std::function& job) { + add_job(job, [] {}); + } + }; + + Worker worker; + void FileCreateSync(const picojson::value& args, picojson::object& out); void FileRename(const picojson::value& args, picojson::object& out); void FileStat(const picojson::value& args, picojson::object& out);