this doesn't compile right now, but is getting closer.
currently trying to resolve the problems in buildor_gen_deps, but may have just found the smoking gun. or bug. bad bug.
//////////////
+basis::mutex &callstack_tracker::__callstack_tracker_synchronizer()
+{
+ static basis::mutex __global_synch_callstacks;
+ return __global_synch_callstacks;
+}
+
+//////////////
+
//! the single instance of callstack_tracker.
-/*! this is also an ultra low-level object, although it's not as far down
+/*!
+ this is also an ultra low-level object, although it's not as far down
as the memory checker. it can allocate c++ objects and that kind of thing
just fine. the object must be stored here rather than in the static basis
library due to issues in windows dlls.
-NOTE: this is also not thread safe; it must be initialized before any threads
-have started. */
+ NOTE: the construction process for this is not thread-safe; the static
+program-wide object must be initialized before any threads have started.
+that is normally done in...
+uhhh....
+
+beuller?
+...
+
-//hmmm: why is this here? because it needs to interact with the progwide memories?
+*/
callstack_tracker &program_wide_stack_trace()
{
+ auto_synchronizer l(callstack_tracker::__callstack_tracker_synchronizer());
+
static callstack_tracker *_hidden_trace = NULL_POINTER;
if (!_hidden_trace) {
#ifdef ENABLE_MEMORY_HOOK
program_wide_memories().disable();
- // we don't want infinite loops tracking the call stack during this
- // object's construction.
+ /* we don't want infinite loops tracking the call stack during this object's construction. */
+//hmmm: does that disable the progwide memories for the whole program or just for this thread?
+// and what does that entail exactly?
+// did it actually fix the problem we saw?
#endif
_hidden_trace = new callstack_tracker;
#ifdef ENABLE_MEMORY_HOOK
bool callstack_tracker::push_frame(const char *class_name, const char *func,
const char *file, int line)
{
+ auto_synchronizer l(callstack_tracker::__callstack_tracker_synchronizer());
+
//printf("callstack pushframe depth=%d in\n", _depth);
if (_unusable) return false;
if (_depth >= MAX_STACK_DEPTH) {
bool callstack_tracker::pop_frame()
{
+ auto_synchronizer l(callstack_tracker::__callstack_tracker_synchronizer());
+
//printf("callstack popframe depth=%d in\n", _depth);
if (_unusable) return false;
if (_depth <= 0) {
bool callstack_tracker::update_line(int line)
{
+ auto_synchronizer l(callstack_tracker::__callstack_tracker_synchronizer());
+
if (_unusable) return false;
if (!_depth) return false; // not as serious, but pretty weird.
_bt->_records[_depth]._line = line;
char *callstack_tracker::full_trace() const
{
+ auto_synchronizer l(callstack_tracker::__callstack_tracker_synchronizer());
+
if (_unusable) return strdup("");
//printf("fulltrace in\n");
char *to_return = (char *)malloc(full_trace_size());
int callstack_tracker::full_trace_size() const
{
+ auto_synchronizer l(callstack_tracker::__callstack_tracker_synchronizer());
+
if (_unusable) return 0;
if (!_depth) return strlen(emptiness_note) + 14; // liberal allocation.
int to_return = 28; // another hollywood style excess.
#include <application/build_configuration.h>
#include <basis/contracts.h>
#include <basis/definitions.h>
+#include <basis/mutex.h>
namespace application {
callstack_tracker &program_wide_stack_trace();
//!< a global object that can be used to track the runtime callstack.
+//hmmm: maybe borked on basis of the conflict between a global stack tracker and the fact that each thread has its own callstack! argh!
+
//////////////
//! This object can provide a backtrace at runtime of the invoking methods.
double highest() const { return _highest; }
//!< reports the maximum stack depth seen during the runtime so far.
+ static basis::mutex &__callstack_tracker_synchronizer();
+ //!< protects concurrent access.
+
private:
callstack_records *_bt; //!< the backtrace records for current program.
int _depth; //!< the current number of frames we know of.
mutex &static_memory_gremlin::__memory_gremlin_synchronizer()
{
- static mutex __globabl_synch_mem;
- return __globabl_synch_mem;
+ static mutex __global_synch_mem;
+ return __global_synch_mem;
}
int static_memory_gremlin::locate(const char *unique_name)
application::program_wide_stack_trace().full_trace_size();
// invoke now to get callback tracking instantiated.
#endif
+
FUNCDEF("HOOPLE_GLOBALS remainder");
// this definition must be postponed until after the objects that would
// track it actually exist.
#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
//hmmm: ugly old main() without using the hoople machinery. ack.
-astring static_class_name() { return "test_path_configuration"; }
+const char *static_class_name() { return "test_path_configuration"; }
HOOPLE_STARTUP_CODE;
using namespace structures;
using namespace unit_test;
-//#define DEBUG_MUTEX
+#define DEBUG_MUTEX
// uncomment for a verbose test run.
const int MAX_MUTEX_TIMING_TEST = 2000000;
{
FUNCDEF("execute");
+#ifdef DEBUG_MUTEX
+ LOG("entering execute method.");
+#endif
+
// make sure the guard is initialized before the threads run.
guard().lock();
guard().unlock();
run_count, full_run_time));
log(a_sprintf("or %f ms per (lock+unlock).", time_per_lock));
ASSERT_TRUE(time_per_lock < 1.0, "mutex lock timing should be super fast");
+#ifdef DEBUG_MUTEX
+ LOG("about to exit scope and dump automatic objects.");
+#endif
}
+#ifdef DEBUG_MUTEX
+ LOG("succeeded in exiting scope.");
+#endif
+
amorph<ethread> thread_list;
for (int i = 0; i < DEFAULT_FISH; i++) {
ethread *t = NULL_POINTER;
- if (i % 2) t = new piranha(*this);
- else t = new barracuda(*this);
+ if (i % 2) {
+ t = new piranha(*this);
+#ifdef DEBUG_MUTEX
+ LOG(a_sprintf("indy %i: adding new piranha now.", i));
+#endif
+ } else {
+ t = new barracuda(*this);
+#ifdef DEBUG_MUTEX
+ LOG(a_sprintf("indy %i: adding new piranha now.", i));
+#endif
+ }
thread_list.append(t);
ethread *q = thread_list[thread_list.elements() - 1];
ASSERT_EQUAL(q, t, "amorph pointer equivalence is required");
+#ifdef DEBUG_MUTEX
+ LOG(a_sprintf("indy %i: about to start new thread.", i));
+#endif
// start the thread we added.
q->start(NULL_POINTER);
+#ifdef DEBUG_MUTEX
+ LOG(a_sprintf("indy %i: after new thread started.", i));
+#endif
}
+#ifdef DEBUG_MUTEX
+ LOG("about to begin snoozing.");
+#endif
+
time_stamp when_to_leave(DEFAULT_RUN_TIME);
while (when_to_leave > time_stamp()) {
time_control::sleep_ms(100);
// that should work fine.
#ifdef DEBUG_MUTEX
- LOG("now cancelling all threads....");
+ LOG("now cancelling all threads.");
#endif
for (int j = 0; j < thread_list.elements(); j++) thread_list[j]->cancel();
#ifdef DEBUG_MUTEX
- LOG("now stopping all threads....");
+ LOG("now stopping all threads.");
#endif
for (int k = 0; k < thread_list.elements(); k++) thread_list[k]->stop();
ASSERT_EQUAL(threads_active, 0, "threads should actually have stopped by now");
#ifdef DEBUG_MUTEX
- LOG("resetting thread list....");
+ LOG("resetting thread list.");
#endif
thread_list.reset(); // should whack all threads.
ASSERT_EQUAL(concurrent_biters, 0, "threads should all be gone by now");
#ifdef DEBUG_MUTEX
- LOG("done exiting from all threads....");
+ LOG("done exiting from all threads.");
LOG(astring(astring::SPRINTF, "the accumulated string had %d characters "
"which means\nthere were %d thread activations from %d threads.",
using namespace timely;
using namespace unit_test;
-//HOOPLE_STARTUP_CODE;
-
//#define DEBUG_STRING_TEST
// uncomment for testing version.
ASSERT_EQUAL(b, a, "second comparison failed");
}
+#define static_class_name() "test_string"
+
void standard_sprintf_test(const char *parm_string)
{
FUNCDEF("standard_sprintf_test");
parm_string, parm_string, basis::un_long(rando.inclusive(0, 2998238)));
}
+#undef static_class_name
+
void test_string::run_test_30()
{
// 30th test group checks astring sprintf.
HOOPLE_MAIN(test_string, )
-
* Please send any updates to: fred@gruntose.com *
\*****************************************************************************/
+#include <algorithms/sorts.h>
#include <application/application_shell.h>
#include <application/command_line.h>
#include <application/hoople_main.h>
#include <sys/stat.h>
-#include "../../library/algorithms/sorts.h"
#ifdef __WIN32__
#include <io.h>
#endif
# methods with a way to know how they were invoked. to get this information.
# the invoker must be fitted with FUNCDEF macros.
ifeq "$(BOOT_STRAPPING)" ""
-# DEFINITIONS += ENABLE_CALLSTACK_TRACKING
+ DEFINITIONS += ENABLE_CALLSTACK_TRACKING
endif
# make sure we haven't already processed this.
local dep="$1"
if seen_already "$dep"; then
-#echo bailing since seen: $dep
+echo bailing since seen: $dep
return 1
fi
-#echo had not seen before: $dep
+echo had not seen before: $dep
# if existing_dep $dep; then return 1; fi # added it to list already.
# if bad_file $dep; then return 1; fi # known to suck.
# if boring_file $dep; then return 1; fi # we already saw it.
-##echo new dep: $dep
+echo new dep: $dep
dependency_accumulator+=($dep)
return 0
# tries to find a filename in the library hierarchy.
function resolve_filename {
local code_file=$1
-#echo resolving: $code_file
+echo "resolving: $code_file"
if [ -f "$code_file" ]; then
# that was pretty easy.
resolve_target_array=($code_file)
return 0
fi
-#echo "MUST seek: $code_file"
+echo "MUST seek: $code_file"
local dir=$(dirname "$code_file")
local base=$(basename "$code_file")
local src_key="$dir/$base"
-#echo "src_key: $src_key"
+echo "src_key: $src_key"
# see if we can find that element in the previously resolved items.
if find_in_array "$src_key" ${resolve_matches_src[*]}; then
local found_indy=$__finders_indy
resolve_target_array=(${resolve_matches_dest[$found_indy]})
-#echo "FOUND \"$src_key\" AT ${resolve_matches_dest[$found_indy]}"
+echo "FOUND \"$src_key\" AT ${resolve_matches_dest[$found_indy]}"
return 0
fi
# reset our global list.
resolve_target_array=()
-#echo "HAVING TO FIND: $dir and $base"
+echo "HAVING TO FIND: $dir and $base"
if [ -z "$dir" ]; then
resolve_target_array=($(find "$BUILD_TOP" -iname "$base"))
else
resolve_target_array=($(find "$BUILD_TOP" -iname "$base" | grep "$dir.$base"))
fi
-#echo resolved to: ${resolve_target_array[*]}
-#echo size of resolve array=${#resolve_target_array[*]}
+echo resolved to: ${resolve_target_array[*]}
+echo size of resolve array=${#resolve_target_array[*]}
if [ ${#resolve_target_array[*]} -eq 1 ]; then
-#echo ADDING a match: $src_key ${resolve_target_array[0]}
+echo ADDING a match: $src_key ${resolve_target_array[0]}
# for unique matches, we will store the correspondence so we can look
# it up very quickly later.
resolve_matches_src+=($src_key)
#hold
#rm "$partial_file"
-#echo "grabbing includes from: $to_examine"
+echo "grabbing includes from: $to_examine"
#hmmm: could separate the find deps on this file stuff below.
# we haven't already.
while read -r line_found; do
local chew_toy=$(echo $line_found | sed -e 's/^[ \t]*#include *<\(.*\)>.*$/\1/')
+ local original_value="$chew_toy"
# we want to add the file to the active list before we forgot about it.
-#echo A: chew_toy=$chew_toy
+echo A: chew_toy=$chew_toy
# check whether the dependency looks like one of our style of includes.
# if it doesn't have a slash in it, then we need to give it the same
if [ ! -z "$(echo $chew_toy | sed -n -e 's/#include/crud/p')" ]; then
# try again with a simpler pattern.
chew_toy=$(echo $line_found | sed -e 's/^[ \t]*#include *[">]\(.*\)[">].*$/\1/')
-#echo B: chew_toy=$chew_toy
+echo B: chew_toy=$chew_toy
# if it still has an #include or if it's not really a file, we can't
# use it for anything.
else
# cool, we can rely on the existing directory.
chew_toy="$fp_dir/$chew_toy"
-#echo patched dir: $chew_toy
+echo patched dir: $chew_toy
fi
fi
fi
if bad_file $chew_toy; then
-#echo C: skipping because on bad list: $chew_toy
+echo C: skipping because on bad list: $chew_toy
continue
fi
#echo odd len is $odd_len
if [ $odd_len -eq 0 ]; then
# whoops. we couldn't find it. probably a system header, so toss it.
-#echo "** ignoring: $chew_toy"
+echo "** ignoring: $chew_toy"
bad_files+=($chew_toy)
chew_toy=""
elif [ $odd_len -eq 1 ]; then
# there's exactly one match, which is very good.
chew_toy="${found_odd[0]}"
-#echo C: chew_toy=$chew_toy
+echo "C: chew_toy=$chew_toy"
else
# this is really wrong. there are multiple files with the same name?
# that kind of things makes debugger tools angry or stupid.
active_deps+=($chew_toy)
fi
fi
+ else
+ echo "** chew_toy was empty! original value was '$original_value'"
fi
# now compute the path as if it was the implementation file (x.cpp)
# instead of being a header. does that file exist? if so, we'd like
# its dependencies also.
- local cpp_toy=$(echo $chew_toy | sed -e 's/^\([^\.]*\)\.h$/\1.cpp/')
+ local cpp_toy=$(echo -n $chew_toy | sed -e 's/^\([^\.]*\)\.h$/\1.cpp/')
+echo "cpp_toy is '$cpp_toy' as derived from chew_toy '$chew_toy'"
# there's no point in adding it if the name didn't change.
if [ "$cpp_toy" != "$chew_toy" ]; then
fi
local new_include=" #include <$chewed_line>"
- echo "$new_include" >>"$pending_deps"
echo "adding '$new_include'"
+ echo "$new_include" >>"$pending_deps"
done
# check that our dependencies file is not empty still.