diff --git a/src/lib/base/finally.h b/src/lib/base/finally.h
new file mode 100644
index 00000000..f3be617c
--- /dev/null
+++ b/src/lib/base/finally.h
@@ -0,0 +1,61 @@
+/*
+ barrier -- mouse and keyboard sharing utility
+ Copyright (C) Barrier contributors
+
+ This package is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ found in the file LICENSE that should have accompanied this file.
+
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef BARRIER_LIB_BASE_FINALLY_H
+#define BARRIER_LIB_BASE_FINALLY_H
+
+#include
+
+namespace barrier {
+
+// this implements a common pattern of executing an action at the end of function
+
+template
+class final_action {
+public:
+ final_action() noexcept {}
+ final_action(Callable callable) noexcept : callable_{callable} {}
+
+ ~final_action() noexcept
+ {
+ if (!invoked_) {
+ callable_();
+ }
+ }
+
+ final_action(final_action&& other) noexcept :
+ callable_{std::move(other.callable_)}
+ {
+ std::swap(invoked_, other.invoked_);
+ }
+
+ final_action(const final_action&) = delete;
+ final_action& operator=(const final_action&) = delete;
+private:
+ bool invoked_ = false;
+ Callable callable_;
+};
+
+template
+inline final_action finally(Callable&& callable) noexcept
+{
+ return final_action(std::forward(callable));
+}
+
+} // namespace barrier
+
+#endif // BARRIER_LIB_BASE_FINALLY_H