/* ///////////////////////////////////////////////////////////////////////// * File: test/component/test.component.be.file.threading/test.component.be.file.threading.cpp * * Purpose: Implementation file for the test.component.be.file.threading project. * * Created: 3rd July 2009 * Updated: 10th January 2011 * * Status: Wizard-generated * * License: (Licensed under the Synesis Software Open License) * * Copyright (c) 2009-2011, Synesis Software Pty Ltd. * All rights reserved. * * www: http://www.synesis.com.au/software * * ////////////////////////////////////////////////////////////////////// */ #include /* Pantheios Header Files */ #include #include #include #include #include #include #include #include #include /* STLSoft Header Files */ #include #include #include #include #include /* Standard C++ Header Files */ #include #if defined(PLATFORMSTL_OS_IS_UNIX) /* PThreads Header Files */ # include # include /* UNIXEm Header Files */ # if defined(_WIN32) || \ defined(_WIN64) # include # endif /* Win32 || Win64 */ #elif defined(PLATFORMSTL_OS_IS_WINDOWS) # define WINSTL_ERROR_DESC_NO_IMPLICIT_CONVERSION # include # include #else /* ? OS */ # error Operating system not discriminated #endif /* OS */ /* Standard C Header Files */ #include #include #if defined(_MSC_VER) && \ defined(_DEBUG) # define USE_MSC_VER_CRT_MEM_CHECKS # include #endif /* _MSC_VER) && _DEBUG */ #include /* ////////////////////////////////////////////////////////////////////// */ #define PSTR(x) PANTHEIOS_LITERAL_STRING(x) /* ///////////////////////////////////////////////////////////////////////// * Character encoding */ #ifdef PANTHEIOS_USE_WIDE_STRINGS # define XTESTS_TEST_STRING_EQUAL XTESTS_TEST_WIDE_STRING_EQUAL #else /* ? PANTHEIOS_USE_WIDE_STRINGS */ # define XTESTS_TEST_STRING_EQUAL XTESTS_TEST_MULTIBYTE_STRING_EQUAL #endif /* PANTHEIOS_USE_WIDE_STRINGS */ /* ///////////////////////////////////////////////////////////////////////// * Constants and definitions */ #ifdef _DEBUG const size_t LOG_ITERATIONS = 10; const size_t SET_PATH_DELAY = 1000 * 100; #else /* ? _DEBUG */ /* Surprisingly, Windows takes massively more time than UNIX to write * out all the entries, so we need different ITERATIONS count otherwise * Windows users running the component tests may think the process has * hung and kill it */ # if defined(PLATFORMSTL_OS_IS_WINDOWS) const size_t LOG_ITERATIONS = 5000; # else /* ? OS */ const size_t LOG_ITERATIONS = 100000; # endif /* OS */ const size_t SET_PATH_DELAY = 1000 * 1000 * 10; #endif /* _DEBUG */ const PAN_CHAR_T LOG_FILE_NAME[] = PSTR("test.component.be.file.threading.log"); /* ///////////////////////////////////////////////////////////////////////// * Globals */ #if defined(PLATFORMSTL_OS_IS_UNIX) static pthread_mutex_t s_mx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t s_cv = PTHREAD_COND_INITIALIZER; static int s_activeThreads = 0; #endif /* OS */ static int s_showNotices = true; extern "C" const PAN_CHAR_T PANTHEIOS_FE_PROCESS_IDENTITY[] = PSTR("test.component.be.file.threading"); /* ///////////////////////////////////////////////////////////////////////// * Typedefs */ #if defined(PLATFORMSTL_OS_IS_UNIX) typedef pthread_t thread_handle_t; #elif defined(PLATFORMSTL_OS_IS_WINDOWS) typedef HANDLE thread_handle_t; #else /* ? OS */ # error Operating system not discriminated #endif /* OS */ typedef platformstl::filesystem_traits fs_traits_t; typedef platformstl::basic_file_lines lines_t; typedef stlsoft::basic_string_view string_view_t; /* ///////////////////////////////////////////////////////////////////////// * Forward declarations */ #if defined(PLATFORMSTL_OS_IS_UNIX) static void* thread_proc(void*); #elif defined(PLATFORMSTL_OS_IS_WINDOWS) static DWORD WINAPI thread_proc(void*); #else /* ? OS */ # error Operating system not discriminated #endif /* OS */ /* ///////////////////////////////////////////////////////////////////////// * Pantheios configuration */ enum { beid_console = 1, beid_file = 2, }; extern "C" { pan_fe_N_t PAN_FE_N_SEVERITY_CEILINGS[] = { #ifdef _DEBUG { beid_console, PANTHEIOS_SEV_NOTICE }, #else /* ? _DEBUG */ { beid_console, PANTHEIOS_SEV_NOTICE }, #endif /* _DEBUG */ { beid_file, PANTHEIOS_SEV_INFORMATIONAL }, PANTHEIOS_FE_N_TERMINATOR_ENTRY(PANTHEIOS_SEV_INFORMATIONAL) }; pan_be_N_t PAN_BE_N_BACKEND_LIST[] = { PANTHEIOS_BE_N_STDFORM_ENTRY(beid_console, pantheios_be_console, PANTHEIOS_BE_N_F_IGNORE_NONMATCHED_CUSTOM28_ID), PANTHEIOS_BE_N_STDFORM_ENTRY(beid_file, pantheios_be_file, PANTHEIOS_BE_N_F_ID_MUST_MATCH_CUSTOM28), PANTHEIOS_BE_N_TERMINATOR_ENTRY }; } // extern "C" /* ////////////////////////////////////////////////////////////////////// */ static int main_(int /*argc*/, char** /*argv*/) { thread_handle_t threads[32]; pan::log_INFORMATIONAL(PSTR("main(): creating "), pan::integer(STLSOFT_NUM_ELEMENTS(threads)), PSTR(" threads")); { for(size_t i = 0; i < STLSOFT_NUM_ELEMENTS(threads); ++i) { void* arg = NULL; #if defined(PLATFORMSTL_OS_IS_UNIX) pthread_mutex_lock(&s_mx); if(0 != pthread_create(&threads[i], NULL, thread_proc, arg)) { pan::log_ALERT(PSTR("Failed to create thread "), pan::integer(i)); pthread_mutex_unlock(&s_mx); return EXIT_FAILURE; } else { pthread_detach(threads[i]); ++s_activeThreads; } pthread_mutex_unlock(&s_mx); #elif defined(PLATFORMSTL_OS_IS_WINDOWS) // NOTE: We are calling the Windows API function CreateThread() // directly, rather than going through beginthreadex() (or // equivalent), which is not the correct thing to do in a real // program, as CRT resources can be leaked. // // We do it this way in this case simply for portability of the // test program DWORD threadId; threads[i] = CreateThread(NULL, 0, thread_proc, arg, 0, &threadId); if(NULL == threads[i]) { winstl::error_desc err; pan::log_ALERT(PSTR("Failed to create thread "), pan::integer(i), PSTR(": "), err); return EXIT_FAILURE; } #else /* ? OS */ # error Operating system not discriminated #endif /* 0 */ }} s_showNotices && pan::log_NOTICE(PSTR("main(): all "), pan::integer(STLSOFT_NUM_ELEMENTS(threads)), PSTR(" threads started")); platformstl::micro_sleep(SET_PATH_DELAY); s_showNotices && pan::log_NOTICE(PSTR("main(): setting log file path")); pantheios_be_file_setFilePath(LOG_FILE_NAME, PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BE_FILE_F_TRUNCATE, 0); s_showNotices && pan::log_NOTICE(PSTR("main(): waiting for threads to complete; this could take several minutes")); #if defined(PLATFORMSTL_OS_IS_UNIX) for(;;) { pthread_mutex_lock(&s_mx); if(0 == s_activeThreads) { pthread_mutex_unlock(&s_mx); break; } else { pthread_cond_wait(&s_cv, &s_mx); } pthread_mutex_unlock(&s_mx); } #elif defined(PLATFORMSTL_OS_IS_WINDOWS) ::WaitForMultipleObjects(STLSOFT_NUM_ELEMENTS(threads), &threads[0], true, INFINITE); #else /* ? OS */ # error Operating system not discriminated #endif /* 0 */ s_showNotices && pan::log_NOTICE(PSTR("main(): all "), pan::integer(STLSOFT_NUM_ELEMENTS(threads)), PSTR(" threads completed")); pantheios_be_file_setFilePath(NULL); int retVal = EXIT_SUCCESS; lines_t lines(LOG_FILE_NAME); { for(size_t i = 0; i != lines.size(); ++i) { lines_t::value_type const& line = lines[i]; string_view_t scratch1; string_view_t scratch2; string_view_t prefix; string_view_t left; string_view_t middle; string_view_t right; if( !stlsoft::split(line, PSTR('|'), prefix, scratch1) || !stlsoft::split(scratch1, PSTR('|'), left, scratch2) || !stlsoft::split(scratch2, PSTR('|'), middle, right)) { pan::log_CRITICAL(PSTR("line does not have required format: ["), pan::integer(i), PSTR(": "), line, PSTR("]")); retVal = EXIT_FAILURE; } else { if(left != right) { pan::log_CRITICAL(PSTR("line prefix and suffix do not match: ["), pan::integer(i), PSTR(": "), line, PSTR("]")); retVal = EXIT_FAILURE; } } }} if(EXIT_SUCCESS == retVal) { s_showNotices && pan::log_NOTICE(PSTR("all lines logged to file correctly")); } else { pan::log_CRITICAL(PSTR("multi-threaded use of be.file has been defective; please report to the Pantheios project")); } return retVal; } #ifdef USE_MSC_VER_CRT_MEM_CHECKS int main__(int argc, char** argv) { _CrtMemState memState; _CrtMemCheckpoint(&memState); int r = main_(argc, argv); _CrtMemDumpAllObjectsSince(&memState); return r; } #else /* ? USE_MSC_VER_CRT_MEM_CHECKS */ # define main__ main_ #endif /* USE_MSC_VER_CRT_MEM_CHECKS */ int main(int argc, char** argv) { if(2 == argc) { char const* arg = argv[1]; if(0 == ::strncmp(arg, "--verbosity=", 12)) { int verbosity = atoi(arg + 12); if(verbosity < 0) { verbosity = 0; } switch(verbosity) { case 0: case 1: s_showNotices = false; break; default: s_showNotices = true; break; } } else { fprintf(stderr, "unrecognised argument: '%s'\n", arg); return EXIT_FAILURE; } } #ifdef STLSOFT_CF_EXCEPTION_SUPPORT try { #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */ int r = main_(argc, argv); fs_traits_t::unlink_file(LOG_FILE_NAME); return r; #ifdef STLSOFT_CF_EXCEPTION_SUPPORT } catch(std::exception& x) { pan::log_ALERT(PSTR("Unexpected general error: "), pantheios::exception(x), PSTR(". Application terminating")); } catch(...) { pan::logputs(pan::emergency, PSTR("Unhandled unknown error")); } #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */ fs_traits_t::unlink_file(LOG_FILE_NAME); return EXIT_FAILURE; } /* ////////////////////////////////////////////////////////////////////// */ #if defined(PLATFORMSTL_OS_IS_UNIX) static void* thread_proc(void*) #elif defined(PLATFORMSTL_OS_IS_WINDOWS) static DWORD WINAPI thread_proc(void*) #endif /* OS */ { #if defined(PLATFORMSTL_OS_IS_UNIX) thread_handle_t self = pthread_self(); #elif defined(PLATFORMSTL_OS_IS_WINDOWS) thread_handle_t self = GetCurrentThread(); #endif /* OS */ pan::log_INFORMATIONAL(PSTR("thread_proc("), pan::blob(&self, sizeof(self)), PSTR("): entering")); // TODO: Do some threading stuff { for(size_t i = 0; i != LOG_ITERATIONS; ++i) { pan::log(pan::informational(beid_file), PSTR("|"), pan::integer(i), PSTR("|"), PSTR("this is"), PSTR(" "), PSTR("multipart log "), PSTR("statement"), PSTR("|"), pan::integer(i)); }} #if defined(PLATFORMSTL_OS_IS_UNIX) pthread_mutex_lock(&s_mx); --s_activeThreads; pthread_cond_signal(&s_cv); pthread_mutex_unlock(&s_mx); #endif /* OS */ pan::log_INFORMATIONAL(PSTR("thread_proc("), pan::blob(&self, sizeof(self)), PSTR("): exiting")); return 0; } /* ////////////////////////////////////////////////////////////////////// */ #if defined(PLATFORMSTL_OS_IS_UNIX) && \ defined(_WIN32) && \ defined(_STLSOFT_FORCE_ANY_COMPILER) # include extern "C" void syslog(char const* s) { OutputDebugStringA(s); } #endif /* ///////////////////////////// end of file //////////////////////////// */