|
From: Carlo W. <li...@us...> - 2002-02-12 05:40:43
|
CVSROOT : /cvsroot/libcw
Module : src
Commit time: 2002-01-12 05:40:42 UTC
Modified files:
libcwd/debug.cc libcwd/threading.cc
libcwd/include/libcw/class_debug.h
libcwd/include/libcw/class_debug.inl libcwd/include/libcw/debug.h
libcwd/include/libcw/macro_ForAllDebugObjects.h
libcwd/include/libcw/private_threading.h libcwd/tests/threads4.cc
Log message:
ostream locking first try.
---------------------- diff included ----------------------
Index: src/libcwd/debug.cc
diff -u src/libcwd/debug.cc:1.66 src/libcwd/debug.cc:1.67
--- src/libcwd/debug.cc:1.66 Sat Feb 9 21:41:58 2002
+++ src/libcwd/debug.cc Mon Feb 11 21:40:31 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/debug.cc,v 1.66 2002/02/10 05:41:58 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/debug.cc,v 1.67 2002/02/12 05:40:31 libcw Exp $
//
// Copyright (C) 2000 - 2001, by
//
@@ -70,7 +70,11 @@
pos_type position;
#endif
public:
+#ifdef LIBCWD_THREAD_SAFE
+ void writeto(std::ostream* os, _private_::lock_interface_base_ct* mutex LIBCWD_COMMA_TSD_PARAM)
+#else
void writeto(std::ostream* os LIBCWD_COMMA_TSD_PARAM)
+#endif
{
char* buf;
bool used_malloc = false;
@@ -91,7 +95,25 @@
++LIBCWD_DO_TSD_MEMBER_OFF(libcw_do);
#endif
LIBCWD_DISABLE_CANCEL // We don't want Dout() to be a cancellation point.
- os->write(buf, curlen);
+ if (mutex)
+ {
+ mutex->lock();
+ os->write(buf, curlen);
+ mutex->unlock();
+ }
+ else if (_private_::WST_multi_threaded)
+ {
+ static bool WST_second_time = false; // Break infinite loop.
+ if (WST_second_time)
+ os->write(buf, curlen);
+ else
+ {
+ WST_second_time = true;
+ DoutFatal(dc::core, "When using multiple threads, you must provide a locking mechanism for the debug output stream. You can pass a pointer to a mutex with `debug_ct::set_ostream'.");
+ }
+ }
+ else
+ os->write(buf, curlen);
LIBCWD_ENABLE_CANCEL
#ifdef DEBUGMALLOC
--LIBCWD_DO_TSD_MEMBER_OFF(libcw_do);
@@ -323,9 +345,6 @@
// Force allocation of a __cxa_eh_globals struct in libsupc++.
(void)std::uncaught_exception();
#endif
-#if defined(DEBUGDEBUG) && defined(LIBCWD_THREAD_SAFE)
- _private_::WST_multi_threaded = true;
-#endif
}
namespace _private_ {
@@ -630,6 +649,12 @@
/** \} */
+#ifdef LIBCWD_THREAD_SAFE
+#define LIBCWD_COMMA_MUTEX ,debug_object.M_mutex
+#else
+#define LIBCWD_COMMA_MUTEX
+#endif
+
void debug_tsd_st::start(debug_ct& debug_object, channel_set_data_st& channel_set LIBCWD_COMMA_TSD_PARAM)
{
#ifdef DEBUGDEBUG
@@ -651,7 +676,23 @@
if (!(current->mask & continued_expected_maskbit))
{
std::ostream* target_os = (channel_set.mask & cerr_cf) ? &std::cerr : debug_object.real_os;
+#ifdef LIBCWD_THREAD_SAFE
+ // Try to get the lock, but don't try too long...
+ int res;
+ struct timespec const t = { 0, 5000000 };
+ for(int count = 0; count < 40; ++count)
+ {
+ res = debug_object.M_mutex->trylock();
+ if (res == 0)
+ break;
+ nanosleep(&t, NULL);
+ }
+#endif
target_os->put('\n');
+#ifdef LIBCWD_THREAD_SAFE
+ if (res == 0)
+ debug_object.M_mutex->unlock();
+#endif
char const* channame = (channel_set.mask & finish_maskbit) ? "finish" : "continued";
#ifdef DEBUGUSEBFD
DoutFatal(dc::core, "Using `dc::" << channame << "' in " <<
@@ -684,11 +725,11 @@
// (current->mask & continued_cf_maskbit) is false and this if is skipped.
LIBCWD_ASSERT( current != reinterpret_cast<laf_ct*>(_private_::WST_dummy_laf) );
#endif
- // Write out what is in the buffer till now.
+ // Append <unfinished> to the current buffer.
+ current_oss->write("<unfinished>\n", 13); // Continued debug output should end on a space by itself,
+ // And write out what is in the buffer till now.
std::ostream* target_os = (channel_set.mask & cerr_cf) ? &std::cerr : debug_object.real_os;
- static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_TSD);
- // Append <unfinished> to it.
- target_os->write("<unfinished>\n", 13); // Continued debug output should end on a space by itself,
+ static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_MUTEX LIBCWD_COMMA_TSD);
// Truncate the buffer to its prefix and append "<continued>" to it already.
static_cast<buffer_ct*>(current_oss)->restore_position();
current_oss->write("<continued> ", 12); // therefore we repeat the space here.
@@ -784,7 +825,7 @@
if ((current->mask & flush_cf))
{
// Write buffer to ostream.
- static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_TSD);
+ static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_MUTEX LIBCWD_COMMA_TSD);
// Flush ostream. Note that in the case of nested debug output this `os' can be an stringstream,
// in that case, no actual flushing is done until the debug output to the real ostream has
// finished.
@@ -804,7 +845,7 @@
current_oss->put('\n');
// Write buffer to ostream.
- static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_TSD);
+ static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_MUTEX LIBCWD_COMMA_TSD);
// Handle control flags, if any:
if (current->mask != 0)
@@ -829,12 +870,18 @@
}
if ((current->mask & wait_cf))
{
+#ifdef LIBCWD_THREAD_SAFE
+ debug_object.M_mutex->lock();
+#endif
*target_os << "(type return)";
if (debug_object.interactive)
{
*target_os << std::flush;
while(std::cin.get() != '\n');
}
+#ifdef LIBCWD_THREAD_SAFE
+ debug_object.M_mutex->unlock();
+#endif
}
if ((current->mask & flush_cf))
{
@@ -906,6 +953,10 @@
if (WNS_initialized)
return;
+#ifdef LIBCWD_THREAD_SAFE
+ M_mutex = NULL;
+#endif
+
#ifdef DEBUGDEBUG
if (!WST_debug_object_init_magic)
init_debug_object_init_magic();
@@ -1466,6 +1517,37 @@
core_dump(); // off() and on() where called and not in equal pairs.
off_cnt = state.off_cnt; // Restore.
}
+
+#ifdef LIBCWD_THREAD_SAFE
+/**
+ * \brief Set output device and provide external pthread mutex.
+ * \ingroup group_destination
+ *
+ * Assign a new \c ostream to this %debug object.
+ * The \c ostream will only be written to after obtaining the lock
+ * that is passed as second argument.
+ *
+ * <b>Example:</b>
+ *
+ * \code
+ * pthread_mutex_t lock;
+ *
+ * // Use the same lock as you use in your application for std::cerr.
+ * Debug( libcw_do.set_ostream(&std::cerr, &lock) );
+ *
+ * pthread_mutex_lock(&lock);
+ * std::cerr << "The application uses cerr too\n";
+ * pthread_mutex_unlock(&lock);
+ * \endcode
+ */
+// Specialization
+template<>
+ void debug_ct::set_ostream(std::ostream* os, pthread_mutex_t* mutex)
+ {
+ M_mutex = new _private_::pthread_lock_interface_ct(mutex);
+ private_set_ostream(os);
+ }
+#endif // LIBCWD_THREAD_SAFE
} // namespace debug
} // namespace libcw
Index: src/libcwd/include/libcw/class_debug.h
diff -u src/libcwd/include/libcw/class_debug.h:1.9 src/libcwd/include/libcw/class_debug.h:1.10
--- src/libcwd/include/libcw/class_debug.h:1.9 Thu Feb 7 20:03:47 2002
+++ src/libcwd/include/libcw/class_debug.h Mon Feb 11 21:40:32 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/class_debug.h,v 1.9 2002/02/08 04:03:47 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/class_debug.h,v 1.10 2002/02/12 05:40:32 libcw Exp $
//
// Copyright (C) 2000 - 2002, by
//
@@ -38,6 +38,10 @@
namespace libcw {
namespace debug {
+namespace _private_ {
+ class lock_interface_base_ct;
+} // namespace _private_
+
//===================================================================================================
// class debug_ct
//
@@ -83,7 +87,13 @@
//
std::ostream* real_os;
- // The original output ostream (as set with set_ostream() or set_fd()).
+ // The original output ostream (as set with set_ostream()).
+ //
+#ifdef LIBCWD_THREAD_SAFE
+ _private_::lock_interface_base_ct* M_mutex;
+ // Pointer to the mutex that should be used for `real_os' or NULL when no lock is used.
+ // A value of NULL is only allowed prior to creating a second thread.
+#endif
private:
//-------------------------------------------------------------------------------------------------
@@ -182,12 +192,24 @@
debug_ct(void);
~debug_ct();
+private:
+ void private_set_ostream(std::ostream* os);
+
public:
//-------------------------------------------------------------------------------------------------
// Manipulators:
//
void set_ostream(std::ostream* os);
+#ifdef LIBCWD_THREAD_SAFE
+ template<class T>
+ void set_ostream(std::ostream* os, T* mutex);
+#ifdef LIBCW_DOXYGEN
+ // Specialization.
+ template<>
+ void set_ostream(std::ostream* os, pthread_mutex_t* mutex);
+#endif
+#endif
void off(void);
void on(void);
@@ -235,8 +257,73 @@
* \returns The previous value.
*/
bool keep_tsd(bool keep);
-#endif
+#endif // LIBCWD_THREAD_SAFE
+};
+
+#ifdef LIBCWD_THREAD_SAFE
+namespace _private_ {
+
+class lock_interface_base_ct {
+public:
+ virtual int trylock(void) = 0;
+ virtual void lock(void) = 0;
+ virtual void unlock(void) = 0;
};
+
+template<class T>
+ class lock_interface_tct : public lock_interface_base_ct {
+ private:
+ T* ptr;
+ virtual int trylock(void) { return ptr->trylock(); }
+ virtual void lock(void) { ptr->lock(); }
+ virtual void unlock(void) { ptr->unlock(); }
+ public:
+ lock_interface_tct(T* mutex) : ptr(mutex) { }
+ };
+
+ class pthread_lock_interface_ct : public lock_interface_base_ct {
+ private:
+ pthread_mutex_t* ptr;
+ virtual int trylock(void) { return pthread_mutex_trylock(ptr); }
+ virtual void lock(void) { pthread_mutex_lock(ptr); }
+ virtual void unlock(void) { pthread_mutex_unlock(ptr); }
+ public:
+ pthread_lock_interface_ct(pthread_mutex_t* mutex) : ptr(mutex) { }
+ };
+
+} // namespace _private_
+
+/**
+ * \brief Set output device and provide external lock.
+ * \ingroup group_destination
+ *
+ * Assign a new \c ostream to this %debug object.
+ * The \c ostream will only be written to after obtaining the lock
+ * that is passed as second argument. Each \c ostream needs to have
+ * a unique lock. If the application also writes directly
+ * to the same \c ostream then use the same lock.
+ *
+ * <b>Example:</b>
+ *
+ * \code
+ * MyLock lock;
+ *
+ * // Uses MyLock::lock(), MyLock::trylock() and MyLock::unlock().
+ * Debug( libcw_do.set_ostream(&std::cerr, &lock) );
+ *
+ * lock.lock();
+ * std::cerr << "The application uses cerr too\n";
+ * lock.unlock();
+ * \endcode
+ */
+template<class T>
+ void debug_ct::set_ostream(std::ostream* os, T* mutex)
+ {
+ M_mutex = new _private_::lock_interface_tct<T>(mutex);
+ private_set_ostream(os);
+ }
+
+#endif // LIBCWD_THREAD_SAFE
} // namespace debug
} // namespace libcw
Index: src/libcwd/include/libcw/class_debug.inl
diff -u src/libcwd/include/libcw/class_debug.inl:1.6 src/libcwd/include/libcw/class_debug.inl:1.7
--- src/libcwd/include/libcw/class_debug.inl:1.6 Tue Feb 5 16:46:08 2002
+++ src/libcwd/include/libcw/class_debug.inl Mon Feb 11 21:40:32 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/class_debug.inl,v 1.6 2002/02/06 00:46:08 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/class_debug.inl,v 1.7 2002/02/12 05:40:32 libcw Exp $
//
// Copyright (C) 2000 - 2001, by
//
@@ -167,15 +167,9 @@
return real_os;
}
-/**
- * \brief Set output device.
- * \ingroup group_destination
- *
- * Assign a new \c ostream to this %debug object (default is <CODE>std::cerr</CODE>).
- */
__inline__
void
-debug_ct::set_ostream(std::ostream* os)
+debug_ct::private_set_ostream(std::ostream* os)
{
real_os = os;
#ifdef DEBUGDEBUG
@@ -184,6 +178,19 @@
if (LIBCWD_TSD_MEMBER(laf_stack).size() == 0)
LIBCWD_TSD_MEMBER(current_oss) = NULL;
#endif
+}
+
+/**
+ * \brief Set output device.
+ * \ingroup group_destination
+ *
+ * Assign a new \c ostream to this %debug object (default is <CODE>std::cerr</CODE>).
+ */
+__inline__
+void
+debug_ct::set_ostream(std::ostream* os)
+{
+ private_set_ostream(os);
}
/** \} */
Index: src/libcwd/include/libcw/debug.h
diff -u src/libcwd/include/libcw/debug.h:1.41 src/libcwd/include/libcw/debug.h:1.42
--- src/libcwd/include/libcw/debug.h:1.41 Fri Feb 8 14:29:29 2002
+++ src/libcwd/include/libcw/debug.h Mon Feb 11 21:40:32 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/debug.h,v 1.41 2002/02/08 22:29:29 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/debug.h,v 1.42 2002/02/12 05:40:32 libcw Exp $
//
// Copyright (C) 2000 - 2001, by
//
@@ -148,15 +148,16 @@
* <b>Examples:</b>
*
* \code
- * Debug( check_configuration() ); // Configuration consistency check.
- * Debug( dc::notice.on() ); // Switch debug channel NOTICE on.
- * Debug( libcw_do.on() ); // Turn all debugging temporally off.
- * Debug( list_channels_on(libcw_do) ); // List all debug channels.
+ * Debug( check_configuration() ); // Configuration consistency check.
+ * Debug( dc::notice.on() ); // Switch debug channel NOTICE on.
+ * Debug( libcw_do.on() ); // Turn all debugging temporally off.
+ * Debug( list_channels_on(libcw_do) ); // List all debug channels.
* Debug( make_all_allocations_invisible_except(NULL) ); // Hide all allocations so far.
- * Debug( list_allocations_on(libcw_do) ); // List all allocations.
- * Debug( libcw_do.set_ostream(&std::cout) ); // Use std::cout as debug output stream.
- * Debug( libcw_do.inc_indent(4) ); // Increment indentation by 4 spaces.
- * Debug( libcw_do.get_ostream()->flush() ); // Flush the current debug output stream.
+ * Debug( list_allocations_on(libcw_do) ); // List all allocations.
+ * Debug( libcw_do.set_ostream(&std::cout) ); // Use std::cout as debug output stream.
+ * Debug( libcw_do.set_ostream(&std::cout, &mutex) ); // use `mutex' as lock for std::cout.
+ * Debug( libcw_do.inc_indent(4) ); // Increment indentation by 4 spaces.
+ * Debug( libcw_do.get_ostream()->flush() ); // Flush the current debug output stream.
* \endcode
*/
#define Debug(x) \
Index: src/libcwd/include/libcw/macro_ForAllDebugObjects.h
diff -u src/libcwd/include/libcw/macro_ForAllDebugObjects.h:1.5 src/libcwd/include/libcw/macro_ForAllDebugObjects.h:1.6
--- src/libcwd/include/libcw/macro_ForAllDebugObjects.h:1.5 Sat Feb 2 20:15:11 2002
+++ src/libcwd/include/libcw/macro_ForAllDebugObjects.h Mon Feb 11 21:40:32 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/macro_ForAllDebugObjects.h,v 1.5 2002/02/03 04:15:11 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/macro_ForAllDebugObjects.h,v 1.6 2002/02/12 05:40:32 libcw Exp $
//
// Copyright (C) 2000 - 2001, by
//
@@ -104,7 +104,7 @@
* For example,
*
* \code
- * ForAllDebugObjects( debugObject.set_ostream(&std::cerr) );
+ * ForAllDebugObjects( debugObject.set_ostream(&std::cerr, &cerr_mutex) );
* \endcode
*
* would set the output stream of all %debug objects to <CODE>std::cerr</CODE>.
Index: src/libcwd/include/libcw/private_threading.h
diff -u src/libcwd/include/libcw/private_threading.h:1.21 src/libcwd/include/libcw/private_threading.h:1.22
--- src/libcwd/include/libcw/private_threading.h:1.21 Thu Feb 7 20:03:47 2002
+++ src/libcwd/include/libcw/private_threading.h Mon Feb 11 21:40:32 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/private_threading.h,v 1.21 2002/02/08 04:03:47 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/private_threading.h,v 1.22 2002/02/12 05:40:32 libcw Exp $
//
// Copyright (C) 2001 - 2002, by
//
@@ -78,9 +78,7 @@
namespace _private_ {
extern void initialize_global_mutexes(void) throw();
-#ifdef DEBUGDEBUG
extern bool WST_multi_threaded;
-#endif
//===================================================================================================
//
Index: src/libcwd/tests/threads4.cc
diff -u src/libcwd/tests/threads4.cc:1.9 src/libcwd/tests/threads4.cc:1.10
--- src/libcwd/tests/threads4.cc:1.9 Tue Feb 5 16:46:08 2002
+++ src/libcwd/tests/threads4.cc Mon Feb 11 21:40:32 2002
@@ -76,7 +76,8 @@
#ifdef DEBUGMALLOC
libcw::debug::make_all_allocations_invisible_except(NULL);
#endif
- Debug( libcw_do.set_ostream(&std::cout) );
+ pthread_mutex_t cout_mutex = PTHREAD_MUTEX_INITIALIZER;
+ Debug( libcw_do.set_ostream(&std::cout, &cout_mutex) );
Debug( libcw_do.on() );
char margin[32];
sprintf(margin, "%-10lu (%04lu) ", pthread_self(), thread_index(pthread_self()));
Index: src/libcwd/threading.cc
diff -u src/libcwd/threading.cc:1.9 src/libcwd/threading.cc:1.10
--- src/libcwd/threading.cc:1.9 Sat Feb 9 21:41:58 2002
+++ src/libcwd/threading.cc Mon Feb 11 21:40:32 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/threading.cc,v 1.9 2002/02/10 05:41:58 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/threading.cc,v 1.10 2002/02/12 05:40:32 libcw Exp $
//
// Copyright (C) 2001, by
//
@@ -22,9 +22,7 @@
namespace _private_ {
#ifdef LIBCWD_THREAD_SAFE
-#ifdef DEBUGDEBUG
bool WST_multi_threaded = false;
-#endif
#ifdef DEBUGDEBUG
int instance_locked[instance_locked_size];
#endif
@@ -86,6 +84,7 @@
mutex_tct<tsd_initialization_instance>::unlock();
if (thread_index(pthread_self()) != 0) // Is this a second (or later) thread?
{
+ WST_multi_threaded = true;
set_alloc_checking_off(*this);
for (int i = 0; i < LIBCWD_DO_MAX; ++i)
if (old_array[i])
----------------------- End of diff -----------------------
|