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

/* /////////////////////////////////////////////////////////////////////////
* 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/util/test/compiler_warnings_suppression.first_include.h>
/* Pantheios Header Files */
#include <pantheios/pan.hpp>
#include <pantheios/backends/be.N.h>
#include <pantheios/backends/bec.console.h>
#include <pantheios/backends/bec.file.h>
#include <pantheios/frontends/fe.N.h>
#include <pantheios/inserters/args.hpp>
#include <pantheios/inserters/blob.hpp>
#include <pantheios/inserters/exception.hpp>
#include <pantheios/inserters/integer.hpp>
/* STLSoft Header Files */
#include <stlsoft/string/split_functions.hpp>
#include <stlsoft/string/string_view.hpp>
#include <platformstl/filesystem/file_lines.hpp>
#include <platformstl/filesystem/filesystem_traits.hpp>
#include <platformstl/synch/sleep_functions.h>
/* Standard C++ Header Files */
#include <exception>
#if defined(PLATFORMSTL_OS_IS_UNIX)
/* PThreads Header Files */
# include <pthread.h>
# include <sched.h>
/* UNIXEm Header Files */
# if defined(_WIN32) || \
defined(_WIN64)
# include <unixem/unixem.h>
# endif /* Win32 || Win64 */
#elif defined(PLATFORMSTL_OS_IS_WINDOWS)
# define WINSTL_ERROR_DESC_NO_IMPLICIT_CONVERSION
# include <winstl/error/error_desc.hpp>
# include <windows.h>
#else /* ? OS */
# error Operating system not discriminated
#endif /* OS */
/* Standard C Header Files */
#include <stdio.h>
#include <stdlib.h>
#if defined(_MSC_VER) && \
defined(_DEBUG)
# define USE_MSC_VER_CRT_MEM_CHECKS
# include <crtdbg.h>
#endif /* _MSC_VER) && _DEBUG */
#include <pantheios/util/test/compiler_warnings_suppression.last_include.h>
/* ////////////////////////////////////////////////////////////////////// */
#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<PAN_CHAR_T> fs_traits_t;
typedef platformstl::basic_file_lines<PAN_CHAR_T> lines_t;
typedef stlsoft::basic_string_view<PAN_CHAR_T> 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 <windows.h>
extern "C" void syslog(char const* s)
{
OutputDebugStringA(s);
}
#endif
/* ///////////////////////////// end of file //////////////////////////// */