hmain_test.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #include "hv.h"
  2. #include "hmain.h"
  3. #include "iniparser.h"
  4. /*
  5. * @build: make examples
  6. * @usage: bin/hmain_test -h
  7. * bin/hmain_test -v
  8. *
  9. * bin/hmain_test -c etc/hmain_test.conf -d
  10. * ps aux | grep hmain_test
  11. *
  12. * bin/hmain_test -s stop
  13. * ps aux | grep hmain_test
  14. *
  15. */
  16. /*
  17. * @介绍:该示例程序展示了一个完整命令行程序所需的功能,包括
  18. * 命令行解析
  19. * 打印帮助信息
  20. * 打印版本信息
  21. * 信号处理
  22. * 解析配置文件
  23. * 写日志
  24. * 后台运行
  25. * 创建pid文件
  26. * 多进程/多线程扩展
  27. *
  28. */
  29. typedef struct conf_ctx_s {
  30. IniParser* parser;
  31. int loglevel;
  32. int worker_processes;
  33. int worker_threads;
  34. int port;
  35. } conf_ctx_t;
  36. conf_ctx_t g_conf_ctx;
  37. inline void conf_ctx_init(conf_ctx_t* ctx) {
  38. ctx->parser = new IniParser;
  39. ctx->loglevel = LOG_LEVEL_DEBUG;
  40. ctx->worker_processes = 0;
  41. ctx->worker_threads = 0;
  42. ctx->port = 0;
  43. }
  44. static void print_version();
  45. static void print_help();
  46. static int parse_confile(const char* confile);
  47. static void worker_fn(void* userdata);
  48. // short options
  49. static const char options[] = "hvc:ts:dp:";
  50. // long options
  51. static const option_t long_options[] = {
  52. {'h', "help", NO_ARGUMENT},
  53. {'v', "version", NO_ARGUMENT},
  54. {'c', "confile", REQUIRED_ARGUMENT},
  55. {'t', "test", NO_ARGUMENT},
  56. {'s', "signal", REQUIRED_ARGUMENT},
  57. {'d', "daemon", NO_ARGUMENT},
  58. {'p', "port", REQUIRED_ARGUMENT}
  59. };
  60. static const char detail_options[] = R"(
  61. -h|--help Print this information
  62. -v|--version Print version
  63. -c|--confile <confile> Set configure file, default etc/{program}.conf
  64. -t|--test Test configure file and exit
  65. -s|--signal <signal> Send <signal> to process,
  66. <signal>=[start,stop,restart,status,reload]
  67. -d|--daemon Daemonize
  68. -p|--port <port> Set listen port
  69. )";
  70. void print_version() {
  71. printf("%s version %s\n", g_main_ctx.program_name, hv_compile_version());
  72. }
  73. void print_help() {
  74. printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
  75. printf("Options:\n%s\n", detail_options);
  76. }
  77. int parse_confile(const char* confile) {
  78. int ret = g_conf_ctx.parser->LoadFromFile(confile);
  79. if (ret != 0) {
  80. printf("Load confile [%s] failed: %d\n", confile, ret);
  81. exit(-40);
  82. }
  83. // logfile
  84. string str = g_conf_ctx.parser->GetValue("logfile");
  85. if (!str.empty()) {
  86. strncpy(g_main_ctx.logfile, str.c_str(), sizeof(g_main_ctx.logfile));
  87. }
  88. hlog_set_file(g_main_ctx.logfile);
  89. // loglevel
  90. str = g_conf_ctx.parser->GetValue("loglevel");
  91. if (!str.empty()) {
  92. hlog_set_level_by_str(str.c_str());
  93. }
  94. // log_filesize
  95. str = g_conf_ctx.parser->GetValue("log_filesize");
  96. if (!str.empty()) {
  97. hlog_set_max_filesize_by_str(str.c_str());
  98. }
  99. // log_remain_days
  100. str = g_conf_ctx.parser->GetValue("log_remain_days");
  101. if (!str.empty()) {
  102. hlog_set_remain_days(atoi(str.c_str()));
  103. }
  104. // log_fsync
  105. str = g_conf_ctx.parser->GetValue("log_fsync");
  106. if (!str.empty()) {
  107. logger_enable_fsync(hlog, getboolean(str.c_str()));
  108. }
  109. // first log here
  110. hlogi("%s version: %s", g_main_ctx.program_name, hv_compile_version());
  111. hlog_fsync();
  112. // worker_processes
  113. int worker_processes = 0;
  114. str = g_conf_ctx.parser->GetValue("worker_processes");
  115. if (str.size() != 0) {
  116. if (strcmp(str.c_str(), "auto") == 0) {
  117. worker_processes = get_ncpu();
  118. hlogd("worker_processes=ncpu=%d", worker_processes);
  119. }
  120. else {
  121. worker_processes = atoi(str.c_str());
  122. }
  123. }
  124. g_conf_ctx.worker_processes = LIMIT(0, worker_processes, MAXNUM_WORKER_PROCESSES);
  125. // worker_threads
  126. int worker_threads = g_conf_ctx.parser->Get<int>("worker_threads");
  127. g_conf_ctx.worker_threads = LIMIT(0, worker_threads, 16);
  128. // port
  129. int port = 0;
  130. const char* szPort = get_arg("p");
  131. if (szPort) {
  132. port = atoi(szPort);
  133. }
  134. if (port == 0) {
  135. port = g_conf_ctx.parser->Get<int>("port");
  136. }
  137. if (port == 0) {
  138. printf("Please config listen port!\n");
  139. exit(-10);
  140. }
  141. g_conf_ctx.port = port;
  142. hlogi("parse_confile('%s') OK", confile);
  143. return 0;
  144. }
  145. static void on_reload(void* userdata) {
  146. hlogi("reload confile [%s]", g_main_ctx.confile);
  147. parse_confile(g_main_ctx.confile);
  148. }
  149. int main(int argc, char** argv) {
  150. // g_main_ctx
  151. main_ctx_init(argc, argv);
  152. if (argc == 1) {
  153. print_help();
  154. exit(10);
  155. }
  156. // int ret = parse_opt(argc, argv, options);
  157. int ret = parse_opt_long(argc, argv, long_options, ARRAY_SIZE(long_options));
  158. if (ret != 0) {
  159. print_help();
  160. exit(ret);
  161. }
  162. /*
  163. printf("---------------arg------------------------------\n");
  164. printf("%s\n", g_main_ctx.cmdline);
  165. for (auto& pair : g_main_ctx.arg_kv) {
  166. printf("%s=%s\n", pair.first.c_str(), pair.second.c_str());
  167. }
  168. for (auto& item : g_main_ctx.arg_list) {
  169. printf("%s\n", item.c_str());
  170. }
  171. printf("================================================\n");
  172. printf("---------------env------------------------------\n");
  173. for (auto& pair : g_main_ctx.env_kv) {
  174. printf("%s=%s\n", pair.first.c_str(), pair.second.c_str());
  175. }
  176. printf("================================================\n");
  177. */
  178. // help
  179. if (get_arg("h")) {
  180. print_help();
  181. exit(0);
  182. }
  183. // version
  184. if (get_arg("v")) {
  185. print_version();
  186. exit(0);
  187. }
  188. // g_conf_ctx
  189. conf_ctx_init(&g_conf_ctx);
  190. const char* confile = get_arg("c");
  191. if (confile) {
  192. strncpy(g_main_ctx.confile, confile, sizeof(g_main_ctx.confile));
  193. }
  194. parse_confile(g_main_ctx.confile);
  195. // test
  196. if (get_arg("t")) {
  197. printf("Test confile [%s] OK!\n", g_main_ctx.confile);
  198. exit(0);
  199. }
  200. // signal
  201. signal_init(on_reload);
  202. const char* signal = get_arg("s");
  203. if (signal) {
  204. signal_handle(signal);
  205. }
  206. #ifdef OS_UNIX
  207. // daemon
  208. if (get_arg("d")) {
  209. // nochdir, noclose
  210. int ret = daemon(1, 1);
  211. if (ret != 0) {
  212. printf("daemon error: %d\n", ret);
  213. exit(-10);
  214. }
  215. }
  216. #endif
  217. // pidfile
  218. create_pidfile();
  219. master_workers_run(worker_fn, (void*)(intptr_t)g_conf_ctx.port, g_conf_ctx.worker_processes, g_conf_ctx.worker_threads);
  220. return 0;
  221. }
  222. void worker_fn(void* userdata) {
  223. long port = (long)(intptr_t)(userdata);
  224. while (1) {
  225. printf("port=%ld pid=%ld tid=%ld\n", port, hv_getpid(), hv_gettid());
  226. hv_delay(60000);
  227. }
  228. }