From 4b7d72629bb5b913b312769bd1757e141928b2de Mon Sep 17 00:00:00 2001
From: lichao <lichao@aiotlink.com>
Date: 星期五, 16 四月 2021 14:27:02 +0800
Subject: [PATCH] add status box function; center run single inst.

---
 box/center_main.cc |   87 ++++++++++++++++++---
 .gitignore         |    8 +-
 box/status_main.cc |  100 +++++++++++++++++++++++++
 3 files changed, 177 insertions(+), 18 deletions(-)

diff --git a/.gitignore b/.gitignore
index 7cf0ce4..6d80560 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,7 @@
 utest/utest
 *.bak
 gmon.out
-box/bhshmqbox
-box/bhshmq_center
-box/help
-utest/bhshmq_center
+*/bhshmq_center
+*/help
+*/bhshmqbox
+*/bhshmq_status
\ No newline at end of file
diff --git a/box/center_main.cc b/box/center_main.cc
index 5baa409..1f181b8 100644
--- a/box/center_main.cc
+++ b/box/center_main.cc
@@ -20,35 +20,94 @@
 #include "center.h"
 #include "defs.h"
 #include "signalhandle.h"
+#include <boost/interprocess/sync/named_mutex.hpp>
 #include <chrono>
 #include <thread>
 using namespace std::chrono_literals;
+using namespace bhome_shm;
 
+namespace
+{
+const std::string kCenterRunningFlag = "bh_center_single_flag_0";
+
+class InstanceFlag
+{
+
+public:
+	InstanceFlag(SharedMemory &shm, const std::string &name) :
+	    shm_(shm), name_(name), run_(false) {}
+	~InstanceFlag() { Stop(); }
+
+	bool TryStartAsFirstInstance()
+	{
+		if (run_) {
+			return true;
+		}
+
+		auto mtx(shm_.find_or_construct<Mutex>((name_ + "_mutex_0").c_str())());
+		auto time_stamp(shm_.find_or_construct<int64_t>((name_ + "_timestamp_0").c_str())(0));
+
+		if (mtx && time_stamp) {
+			Guard lock(*mtx);
+			auto now = NowSec();
+			// printf("old: %ld, now: %ld\n", *time_stamp, now);
+			if (now > *time_stamp + 10) {
+				*time_stamp = now;
+				auto UpdateTime = [this, time_stamp]() {
+					while (run_) {
+						std::this_thread::sleep_for(1s);
+						*time_stamp = NowSec();
+					}
+				};
+				run_.store(true);
+				std::thread(UpdateTime).swap(worker_);
+				return true;
+			}
+		}
+		return false;
+	}
+
+private:
+	void Stop()
+	{
+		run_.store(false);
+		if (worker_.joinable()) {
+			worker_.join();
+		}
+	}
+
+	std::thread worker_;
+	SharedMemory &shm_;
+	std::string name_;
+	std::atomic<bool> run_;
+};
+
+} // namespace
 int center_main(int argc, const char *argv[])
 {
+	auto &shm = BHomeShm();
+
 	AppArg args(argc, argv);
 	if (args.Has("remove")) {
-		BHomeShm().Remove();
+		shm.Remove();
 		return 0;
 	}
 
-	bool run = true;
-	auto showStatus = [&]() {
-		auto init = BHomeShm().get_free_memory();
-		uint64_t idx = 0;
-		while (run) {
-			std::this_thread::sleep_for(1s);
-			printf("%8d shared memory: avail : %ld / %ld\n", ++idx, BHomeShm().get_free_memory(), init);
-		}
-	};
-	std::thread t(showStatus);
+	InstanceFlag inst(shm, kCenterRunningFlag);
+	if (!inst.TryStartAsFirstInstance()) {
+		printf("another instance is running, exit.\n");
+		return 0;
+	}
 
-	BHCenter center(BHomeShm());
+	if (args.Has("daemon") || args.Has("d")) {
+		int r = daemon(0, 0); // TODO center control msg to close itself.
+	}
+
+	BHCenter center(shm);
 	center.Start();
+
 	printf("center started ...\n");
 	WaitForSignals({SIGINT, SIGTERM});
-	run = false;
-	t.join();
 	return 0;
 }
 
diff --git a/box/status_main.cc b/box/status_main.cc
new file mode 100644
index 0000000..993fbee
--- /dev/null
+++ b/box/status_main.cc
@@ -0,0 +1,100 @@
+/*
+ * =====================================================================================
+ *
+ *       Filename:  status_main.cc
+ *
+ *    Description:  
+ *
+ *        Version:  1.0
+ *        Created:  2021骞�04鏈�16鏃� 12鏃�17鍒�07绉�
+ *       Revision:  none
+ *       Compiler:  gcc
+ *
+ *         Author:  Li Chao (), lichao@aiotlink.com
+ *   Organization:  
+ *
+ * =====================================================================================
+ */
+
+#include "app_arg.h"
+#include "box.h"
+#include "defs.h"
+#include "shm.h"
+#include "signalhandle.h"
+#include <atomic>
+#include <chrono>
+#include <thread>
+
+using namespace std::chrono_literals;
+using namespace std::chrono;
+using namespace bhome_shm;
+
+int status_main(int argc, char const *argv[])
+{
+	auto &shm = BHomeShm();
+
+	std::atomic<bool> run(true);
+
+	auto Now = []() { return steady_clock::now(); };
+	auto ToMs = [](auto tp) { return duration_cast<milliseconds>(tp.time_since_epoch()).count(); };
+
+	auto showStatus = [&]() {
+		auto next = Now();
+		const uint64_t start = ToMs(next);
+		auto last = 0;
+		while (run) {
+			std::this_thread::sleep_until(next);
+			auto passed = ToMs(next) - start;
+			auto sec = passed / 1000;
+
+			auto cur = shm.get_free_memory();
+
+			auto Pretty = [](int64_t nbyte) {
+				char sign = '+';
+				if (nbyte < 0) {
+					nbyte = -nbyte;
+					sign = '-';
+				}
+				const int Kb = 1024;
+				const int Mb = Kb * 1024;
+				int nmb = nbyte / Mb;
+				auto left = nbyte - nmb * Mb;
+				int nkb = left / Kb;
+				int nb = left - nkb * Kb;
+				char buf[64] = {0};
+				int n = sprintf(buf, " %4dMb %4dKb %4dB", nmb, nkb, nb);
+				int start = (nmb > 0) ? 0 : ((nkb > 0) ? 7 : 14);
+				buf[start] = sign;
+				return std::string(buf + start);
+			};
+
+			char buf[200] = "\n";
+			auto Print = [&](bool new_line) {
+				int n = sprintf(buf, "\r%6ds avail : %12ld = %s %6ds", sec, cur, Pretty(cur).c_str() + 1, sec);
+				printf("%s", buf);
+				if (new_line) {
+					auto diff = cur - last;
+					printf(" (%+ld = %s)\n", diff, Pretty(diff).c_str());
+					printf("%s", buf);
+				}
+				fflush(stdout);
+			};
+			Print(cur != last);
+			last = cur;
+			next += 1000ms;
+		}
+	};
+
+	std::thread t(showStatus);
+
+	WaitForSignals({SIGINT, SIGTERM});
+	run.store(false);
+	t.join();
+
+	return 0;
+}
+
+namespace
+{
+static bool install = BoxInstall("bhshmq_status", status_main, "bhome status program.");
+}

--
Gitblit v1.8.0