You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

486 lines
13 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: test/component/test.component.be.file.threading/test.component.be.file.threading.cpp
  3. *
  4. * Purpose: Implementation file for the test.component.be.file.threading project.
  5. *
  6. * Created: 3rd July 2009
  7. * Updated: 10th January 2011
  8. *
  9. * Status: Wizard-generated
  10. *
  11. * License: (Licensed under the Synesis Software Open License)
  12. *
  13. * Copyright (c) 2009-2011, Synesis Software Pty Ltd.
  14. * All rights reserved.
  15. *
  16. * www: http://www.synesis.com.au/software
  17. *
  18. * ////////////////////////////////////////////////////////////////////// */
  19. #include <pantheios/util/test/compiler_warnings_suppression.first_include.h>
  20. /* Pantheios Header Files */
  21. #include <pantheios/pan.hpp>
  22. #include <pantheios/backends/be.N.h>
  23. #include <pantheios/backends/bec.console.h>
  24. #include <pantheios/backends/bec.file.h>
  25. #include <pantheios/frontends/fe.N.h>
  26. #include <pantheios/inserters/args.hpp>
  27. #include <pantheios/inserters/blob.hpp>
  28. #include <pantheios/inserters/exception.hpp>
  29. #include <pantheios/inserters/integer.hpp>
  30. /* STLSoft Header Files */
  31. #include <stlsoft/string/split_functions.hpp>
  32. #include <stlsoft/string/string_view.hpp>
  33. #include <platformstl/filesystem/file_lines.hpp>
  34. #include <platformstl/filesystem/filesystem_traits.hpp>
  35. #include <platformstl/synch/sleep_functions.h>
  36. /* Standard C++ Header Files */
  37. #include <exception>
  38. #if defined(PLATFORMSTL_OS_IS_UNIX)
  39. /* PThreads Header Files */
  40. # include <pthread.h>
  41. # include <sched.h>
  42. /* UNIXEm Header Files */
  43. # if defined(_WIN32) || \
  44. defined(_WIN64)
  45. # include <unixem/unixem.h>
  46. # endif /* Win32 || Win64 */
  47. #elif defined(PLATFORMSTL_OS_IS_WINDOWS)
  48. # define WINSTL_ERROR_DESC_NO_IMPLICIT_CONVERSION
  49. # include <winstl/error/error_desc.hpp>
  50. # include <windows.h>
  51. #else /* ? OS */
  52. # error Operating system not discriminated
  53. #endif /* OS */
  54. /* Standard C Header Files */
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #if defined(_MSC_VER) && \
  58. defined(_DEBUG)
  59. # define USE_MSC_VER_CRT_MEM_CHECKS
  60. # include <crtdbg.h>
  61. #endif /* _MSC_VER) && _DEBUG */
  62. #include <pantheios/util/test/compiler_warnings_suppression.last_include.h>
  63. /* ////////////////////////////////////////////////////////////////////// */
  64. #define PSTR(x) PANTHEIOS_LITERAL_STRING(x)
  65. /* /////////////////////////////////////////////////////////////////////////
  66. * Character encoding
  67. */
  68. #ifdef PANTHEIOS_USE_WIDE_STRINGS
  69. # define XTESTS_TEST_STRING_EQUAL XTESTS_TEST_WIDE_STRING_EQUAL
  70. #else /* ? PANTHEIOS_USE_WIDE_STRINGS */
  71. # define XTESTS_TEST_STRING_EQUAL XTESTS_TEST_MULTIBYTE_STRING_EQUAL
  72. #endif /* PANTHEIOS_USE_WIDE_STRINGS */
  73. /* /////////////////////////////////////////////////////////////////////////
  74. * Constants and definitions
  75. */
  76. #ifdef _DEBUG
  77. const size_t LOG_ITERATIONS = 10;
  78. const size_t SET_PATH_DELAY = 1000 * 100;
  79. #else /* ? _DEBUG */
  80. /* Surprisingly, Windows takes massively more time than UNIX to write
  81. * out all the entries, so we need different ITERATIONS count otherwise
  82. * Windows users running the component tests may think the process has
  83. * hung and kill it
  84. */
  85. # if defined(PLATFORMSTL_OS_IS_WINDOWS)
  86. const size_t LOG_ITERATIONS = 5000;
  87. # else /* ? OS */
  88. const size_t LOG_ITERATIONS = 100000;
  89. # endif /* OS */
  90. const size_t SET_PATH_DELAY = 1000 * 1000 * 10;
  91. #endif /* _DEBUG */
  92. const PAN_CHAR_T LOG_FILE_NAME[] = PSTR("test.component.be.file.threading.log");
  93. /* /////////////////////////////////////////////////////////////////////////
  94. * Globals
  95. */
  96. #if defined(PLATFORMSTL_OS_IS_UNIX)
  97. static pthread_mutex_t s_mx = PTHREAD_MUTEX_INITIALIZER;
  98. static pthread_cond_t s_cv = PTHREAD_COND_INITIALIZER;
  99. static int s_activeThreads = 0;
  100. #endif /* OS */
  101. static int s_showNotices = true;
  102. extern "C" const PAN_CHAR_T PANTHEIOS_FE_PROCESS_IDENTITY[] = PSTR("test.component.be.file.threading");
  103. /* /////////////////////////////////////////////////////////////////////////
  104. * Typedefs
  105. */
  106. #if defined(PLATFORMSTL_OS_IS_UNIX)
  107. typedef pthread_t thread_handle_t;
  108. #elif defined(PLATFORMSTL_OS_IS_WINDOWS)
  109. typedef HANDLE thread_handle_t;
  110. #else /* ? OS */
  111. # error Operating system not discriminated
  112. #endif /* OS */
  113. typedef platformstl::filesystem_traits<PAN_CHAR_T> fs_traits_t;
  114. typedef platformstl::basic_file_lines<PAN_CHAR_T> lines_t;
  115. typedef stlsoft::basic_string_view<PAN_CHAR_T> string_view_t;
  116. /* /////////////////////////////////////////////////////////////////////////
  117. * Forward declarations
  118. */
  119. #if defined(PLATFORMSTL_OS_IS_UNIX)
  120. static void* thread_proc(void*);
  121. #elif defined(PLATFORMSTL_OS_IS_WINDOWS)
  122. static DWORD WINAPI thread_proc(void*);
  123. #else /* ? OS */
  124. # error Operating system not discriminated
  125. #endif /* OS */
  126. /* /////////////////////////////////////////////////////////////////////////
  127. * Pantheios configuration
  128. */
  129. enum
  130. {
  131. beid_console = 1,
  132. beid_file = 2,
  133. };
  134. extern "C"
  135. {
  136. pan_fe_N_t PAN_FE_N_SEVERITY_CEILINGS[] =
  137. {
  138. #ifdef _DEBUG
  139. { beid_console, PANTHEIOS_SEV_NOTICE },
  140. #else /* ? _DEBUG */
  141. { beid_console, PANTHEIOS_SEV_NOTICE },
  142. #endif /* _DEBUG */
  143. { beid_file, PANTHEIOS_SEV_INFORMATIONAL },
  144. PANTHEIOS_FE_N_TERMINATOR_ENTRY(PANTHEIOS_SEV_INFORMATIONAL)
  145. };
  146. pan_be_N_t PAN_BE_N_BACKEND_LIST[] =
  147. {
  148. PANTHEIOS_BE_N_STDFORM_ENTRY(beid_console, pantheios_be_console, PANTHEIOS_BE_N_F_IGNORE_NONMATCHED_CUSTOM28_ID),
  149. PANTHEIOS_BE_N_STDFORM_ENTRY(beid_file, pantheios_be_file, PANTHEIOS_BE_N_F_ID_MUST_MATCH_CUSTOM28),
  150. PANTHEIOS_BE_N_TERMINATOR_ENTRY
  151. };
  152. } // extern "C"
  153. /* ////////////////////////////////////////////////////////////////////// */
  154. static int main_(int /*argc*/, char** /*argv*/)
  155. {
  156. thread_handle_t threads[32];
  157. pan::log_INFORMATIONAL(PSTR("main(): creating "), pan::integer(STLSOFT_NUM_ELEMENTS(threads)), PSTR(" threads"));
  158. { for(size_t i = 0; i < STLSOFT_NUM_ELEMENTS(threads); ++i)
  159. {
  160. void* arg = NULL;
  161. #if defined(PLATFORMSTL_OS_IS_UNIX)
  162. pthread_mutex_lock(&s_mx);
  163. if(0 != pthread_create(&threads[i], NULL, thread_proc, arg))
  164. {
  165. pan::log_ALERT(PSTR("Failed to create thread "), pan::integer(i));
  166. pthread_mutex_unlock(&s_mx);
  167. return EXIT_FAILURE;
  168. }
  169. else
  170. {
  171. pthread_detach(threads[i]);
  172. ++s_activeThreads;
  173. }
  174. pthread_mutex_unlock(&s_mx);
  175. #elif defined(PLATFORMSTL_OS_IS_WINDOWS)
  176. // NOTE: We are calling the Windows API function CreateThread()
  177. // directly, rather than going through beginthreadex() (or
  178. // equivalent), which is not the correct thing to do in a real
  179. // program, as CRT resources can be leaked.
  180. //
  181. // We do it this way in this case simply for portability of the
  182. // test program
  183. DWORD threadId;
  184. threads[i] = CreateThread(NULL, 0, thread_proc, arg, 0, &threadId);
  185. if(NULL == threads[i])
  186. {
  187. winstl::error_desc err;
  188. pan::log_ALERT(PSTR("Failed to create thread "), pan::integer(i), PSTR(": "), err);
  189. return EXIT_FAILURE;
  190. }
  191. #else /* ? OS */
  192. # error Operating system not discriminated
  193. #endif /* 0 */
  194. }}
  195. s_showNotices &&
  196. pan::log_NOTICE(PSTR("main(): all "), pan::integer(STLSOFT_NUM_ELEMENTS(threads)), PSTR(" threads started"));
  197. platformstl::micro_sleep(SET_PATH_DELAY);
  198. s_showNotices &&
  199. pan::log_NOTICE(PSTR("main(): setting log file path"));
  200. pantheios_be_file_setFilePath(LOG_FILE_NAME, PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BE_FILE_F_TRUNCATE, 0);
  201. s_showNotices &&
  202. pan::log_NOTICE(PSTR("main(): waiting for threads to complete; this could take several minutes"));
  203. #if defined(PLATFORMSTL_OS_IS_UNIX)
  204. for(;;)
  205. {
  206. pthread_mutex_lock(&s_mx);
  207. if(0 == s_activeThreads)
  208. {
  209. pthread_mutex_unlock(&s_mx);
  210. break;
  211. }
  212. else
  213. {
  214. pthread_cond_wait(&s_cv, &s_mx);
  215. }
  216. pthread_mutex_unlock(&s_mx);
  217. }
  218. #elif defined(PLATFORMSTL_OS_IS_WINDOWS)
  219. ::WaitForMultipleObjects(STLSOFT_NUM_ELEMENTS(threads), &threads[0], true, INFINITE);
  220. #else /* ? OS */
  221. # error Operating system not discriminated
  222. #endif /* 0 */
  223. s_showNotices &&
  224. pan::log_NOTICE(PSTR("main(): all "), pan::integer(STLSOFT_NUM_ELEMENTS(threads)), PSTR(" threads completed"));
  225. pantheios_be_file_setFilePath(NULL);
  226. int retVal = EXIT_SUCCESS;
  227. lines_t lines(LOG_FILE_NAME);
  228. { for(size_t i = 0; i != lines.size(); ++i)
  229. {
  230. lines_t::value_type const& line = lines[i];
  231. string_view_t scratch1;
  232. string_view_t scratch2;
  233. string_view_t prefix;
  234. string_view_t left;
  235. string_view_t middle;
  236. string_view_t right;
  237. if( !stlsoft::split(line, PSTR('|'), prefix, scratch1) ||
  238. !stlsoft::split(scratch1, PSTR('|'), left, scratch2) ||
  239. !stlsoft::split(scratch2, PSTR('|'), middle, right))
  240. {
  241. pan::log_CRITICAL(PSTR("line does not have required format: ["), pan::integer(i), PSTR(": "), line, PSTR("]"));
  242. retVal = EXIT_FAILURE;
  243. }
  244. else
  245. {
  246. if(left != right)
  247. {
  248. pan::log_CRITICAL(PSTR("line prefix and suffix do not match: ["), pan::integer(i), PSTR(": "), line, PSTR("]"));
  249. retVal = EXIT_FAILURE;
  250. }
  251. }
  252. }}
  253. if(EXIT_SUCCESS == retVal)
  254. {
  255. s_showNotices &&
  256. pan::log_NOTICE(PSTR("all lines logged to file correctly"));
  257. }
  258. else
  259. {
  260. pan::log_CRITICAL(PSTR("multi-threaded use of be.file has been defective; please report to the Pantheios project"));
  261. }
  262. return retVal;
  263. }
  264. #ifdef USE_MSC_VER_CRT_MEM_CHECKS
  265. int main__(int argc, char** argv)
  266. {
  267. _CrtMemState memState;
  268. _CrtMemCheckpoint(&memState);
  269. int r = main_(argc, argv);
  270. _CrtMemDumpAllObjectsSince(&memState);
  271. return r;
  272. }
  273. #else /* ? USE_MSC_VER_CRT_MEM_CHECKS */
  274. # define main__ main_
  275. #endif /* USE_MSC_VER_CRT_MEM_CHECKS */
  276. int main(int argc, char** argv)
  277. {
  278. if(2 == argc)
  279. {
  280. char const* arg = argv[1];
  281. if(0 == ::strncmp(arg, "--verbosity=", 12))
  282. {
  283. int verbosity = atoi(arg + 12);
  284. if(verbosity < 0)
  285. {
  286. verbosity = 0;
  287. }
  288. switch(verbosity)
  289. {
  290. case 0:
  291. case 1:
  292. s_showNotices = false;
  293. break;
  294. default:
  295. s_showNotices = true;
  296. break;
  297. }
  298. }
  299. else
  300. {
  301. fprintf(stderr, "unrecognised argument: '%s'\n", arg);
  302. return EXIT_FAILURE;
  303. }
  304. }
  305. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  306. try
  307. {
  308. #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */
  309. int r = main_(argc, argv);
  310. fs_traits_t::unlink_file(LOG_FILE_NAME);
  311. return r;
  312. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  313. }
  314. catch(std::exception& x)
  315. {
  316. pan::log_ALERT(PSTR("Unexpected general error: "), pantheios::exception(x), PSTR(". Application terminating"));
  317. }
  318. catch(...)
  319. {
  320. pan::logputs(pan::emergency, PSTR("Unhandled unknown error"));
  321. }
  322. #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */
  323. fs_traits_t::unlink_file(LOG_FILE_NAME);
  324. return EXIT_FAILURE;
  325. }
  326. /* ////////////////////////////////////////////////////////////////////// */
  327. #if defined(PLATFORMSTL_OS_IS_UNIX)
  328. static void* thread_proc(void*)
  329. #elif defined(PLATFORMSTL_OS_IS_WINDOWS)
  330. static DWORD WINAPI thread_proc(void*)
  331. #endif /* OS */
  332. {
  333. #if defined(PLATFORMSTL_OS_IS_UNIX)
  334. thread_handle_t self = pthread_self();
  335. #elif defined(PLATFORMSTL_OS_IS_WINDOWS)
  336. thread_handle_t self = GetCurrentThread();
  337. #endif /* OS */
  338. pan::log_INFORMATIONAL(PSTR("thread_proc("), pan::blob(&self, sizeof(self)), PSTR("): entering"));
  339. // TODO: Do some threading stuff
  340. { for(size_t i = 0; i != LOG_ITERATIONS; ++i)
  341. {
  342. pan::log(pan::informational(beid_file), PSTR("|"), pan::integer(i), PSTR("|"), PSTR("this is"), PSTR(" "), PSTR("multipart log "), PSTR("statement"), PSTR("|"), pan::integer(i));
  343. }}
  344. #if defined(PLATFORMSTL_OS_IS_UNIX)
  345. pthread_mutex_lock(&s_mx);
  346. --s_activeThreads;
  347. pthread_cond_signal(&s_cv);
  348. pthread_mutex_unlock(&s_mx);
  349. #endif /* OS */
  350. pan::log_INFORMATIONAL(PSTR("thread_proc("), pan::blob(&self, sizeof(self)), PSTR("): exiting"));
  351. return 0;
  352. }
  353. /* ////////////////////////////////////////////////////////////////////// */
  354. #if defined(PLATFORMSTL_OS_IS_UNIX) && \
  355. defined(_WIN32) && \
  356. defined(_STLSOFT_FORCE_ANY_COMPILER)
  357. # include <windows.h>
  358. extern "C" void syslog(char const* s)
  359. {
  360. OutputDebugStringA(s);
  361. }
  362. #endif
  363. /* ///////////////////////////// end of file //////////////////////////// */