[Spread-cvs] commit: r469 - in libspreadutil/trunk: . src
jonathan at spread.org
jonathan at spread.org
Tue Jan 31 00:26:05 EST 2012
Author: jonathan
Date: 2012-01-31 00:26:05 -0500 (Tue, 31 Jan 2012)
New Revision: 469
Added:
libspreadutil/trunk/Changelog
libspreadutil/trunk/src/alarm_types.h
libspreadutil/trunk/src/arch.c
Modified:
libspreadutil/trunk/configure
libspreadutil/trunk/configure.in
libspreadutil/trunk/src/alarm.c
libspreadutil/trunk/src/alarm.h
libspreadutil/trunk/src/arch.h
libspreadutil/trunk/src/data_link.c
libspreadutil/trunk/src/data_link.h
libspreadutil/trunk/src/events.c
libspreadutil/trunk/src/memory.c
libspreadutil/trunk/src/memory.h
libspreadutil/trunk/src/sp_events.h
Log:
Add features and fixes from other branches of utility code. See Changelog for details. Not fully integrated with standalong utiliyt library so work in progress.
Added: libspreadutil/trunk/Changelog
===================================================================
--- libspreadutil/trunk/Changelog (rev 0)
+++ libspreadutil/trunk/Changelog 2012-01-31 05:26:05 UTC (rev 469)
@@ -0,0 +1,27 @@
+
+January 30, 2012
+----------------
+To that baseline we added the following features:
+
+ - Monitoring slow events (ones that take too long) in the evenst code and providing an API to access the data about them.
+ - Using a monotonic clock in the events code when one is available. If not it falls back to the previous methods.
+ - New E_in_queue() function to query whether a scheduled event is already in the event system.
+ - Adding abilty for Alarm calls to be pushed through a queue to another thread for writing to disk. This takes slow disk IO out of the Alarm fastpath.
+ - Better multicast routing handling in data_link.c
+ - Added NO_LOOP option to datalink channel creation function to prevent user from recieving their own multicast packets back in DL_recv.
+ - Added reference counting to memory.c allocated objects. Not used by default, but can be activated on an object-by-object basis with the new API functions.
+ - Added Windows implmentation of sock_strerror() and generic implementation of strerror().
+ - John Schultz's rewrite of alarm.c with lots of clean ups.
+ - Add realtime alerting hook to alarms.
+ - Change to high precision timestamp capability of Alarm, it is now enabled by Alarm_enable_timestamp_high_res() function instaed of Alarm_enable_precise_timestamps().
+ + all changes in Spread changelog from version 4.1 until those committed on 1/28/2012.
+
+January 20,2012
+---------------
+Baseline is Spread 4.1 release version of following source files and their corresponding headers:
+ events.c
+ data_link.c
+ alarm.c
+ memory.c
+
+ and the required headers and build files for the configure scripts and portability headers.
Modified: libspreadutil/trunk/configure
===================================================================
--- libspreadutil/trunk/configure 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/configure 2012-01-31 05:26:05 UTC (rev 469)
@@ -5977,6 +5977,167 @@
fi
+
+{ $as_echo "$as_me:$LINENO: checking for library containing dladdr" >&5
+$as_echo_n "checking for library containing dladdr... " >&6; }
+if test "${ac_cv_search_dladdr+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dladdr ();
+int
+main ()
+{
+return dladdr ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' dl dld; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ ac_cv_search_dladdr=$ac_res
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ if test "${ac_cv_search_dladdr+set}" = set; then
+ break
+fi
+done
+if test "${ac_cv_search_dladdr+set}" = set; then
+ :
+else
+ ac_cv_search_dladdr=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_dladdr" >&5
+$as_echo "$ac_cv_search_dladdr" >&6; }
+ac_res=$ac_cv_search_dladdr
+if test "$ac_res" != no; then
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else
+
+ { { $as_echo "$as_me:$LINENO: error: unable to find the dladdr() function" >&5
+$as_echo "$as_me: error: unable to find the dladdr() function" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking for dladdr" >&5
+$as_echo_n "checking for dladdr... " >&6; }
+if test "${ac_cv_have_dladdr+set}" = set; then
+ $as_echo_n "(cached) " >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+ #ifndef _GNU_SOURCE
+ #define _GNU_SOURCE 1
+ #endif
+ #include <dlfcn.h>
+int
+main ()
+{
+ Dl_info* info = 0;
+ dladdr(0, info);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_have_dladdr="yes"
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_have_dladdr="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_have_dladdr" >&5
+$as_echo "$ac_cv_have_dladdr" >&6; }
+
+if test "x$ac_cv_have_dladdr" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DLADDR 1
+_ACEOF
+
+fi
+
# Check for broken snprintf
if test "x$ac_cv_func_snprintf" = "xyes" ; then
{ $as_echo "$as_me:$LINENO: checking whether snprintf correctly terminates long strings" >&5
Modified: libspreadutil/trunk/configure.in
===================================================================
--- libspreadutil/trunk/configure.in 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/configure.in 2012-01-31 05:26:05 UTC (rev 469)
@@ -121,6 +121,30 @@
AC_DEFINE(HAVE_CLOCK_GETTIME_CLOCK_MONOTONIC, 1, [Have clock_gettime(CLOCK_MONOTONIC, ...)!])
fi
+
+dnl Check for dladdr function in different libraries
+AC_SEARCH_LIBS([dladdr], [dl dld], [], [
+ AC_MSG_ERROR([unable to find the dladdr() function])
+ ])
+
+dnl Check for dladdr so code can be condititionally defined if not present
+AC_CACHE_CHECK([for dladdr], ac_cv_have_dladdr, [
+ AC_TRY_COMPILE(
+ [ #ifndef _GNU_SOURCE
+ #define _GNU_SOURCE 1
+ #endif
+ #include <dlfcn.h> ],
+ [ Dl_info* info = 0;
+ dladdr(0, info); ],
+ [ ac_cv_have_dladdr="yes" ],
+ [ ac_cv_have_dladdr="no" ]
+ )
+])
+
+if test "x$ac_cv_have_dladdr" = "xyes" ; then
+ AC_DEFINE(HAVE_DLADDR, 1, dladdr function)
+fi
+
# Check for broken snprintf
if test "x$ac_cv_func_snprintf" = "xyes" ; then
AC_MSG_CHECKING([whether snprintf correctly terminates long strings])
Modified: libspreadutil/trunk/src/alarm.c
===================================================================
--- libspreadutil/trunk/src/alarm.c 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/src/alarm.c 2012-01-31 05:26:05 UTC (rev 469)
@@ -37,168 +37,298 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <assert.h>
/* undef redefined variables under windows */
#ifdef ARCH_PC_WIN95
-#undef EINTR
-#undef EAGAIN
-#undef EWOULDBLOCK
-#undef EINPROGRESS
+# undef EINTR
+# undef EAGAIN
+# undef EWOULDBLOCK
+# undef EINPROGRESS
#endif
#include <errno.h>
#ifdef HAVE_GOOD_VARGS
-#include <stdarg.h>
+# include <stdarg.h>
#endif
#include "alarm.h"
-
#include "sp_events.h"
-static int32 Alarm_type_mask = PRINT | EXIT ;
-static int16 Alarm_cur_priority = SPLOG_DEBUG ;
+#define MAX_ALARM_MESSAGE_BUF 256
-static char *Alarm_timestamp_format = NULL;
+static const char Alarm_Warning_High_Res[] = "*** WARNING *** Alarmp: High precision timestamp output failed!\n";
+static const char Alarm_Warning_Timestamp[] = "*** WARNING *** Alarmp: Timestamp didn't fit in default size buffer!\n";
+static const char Alarm_Warning_Alloc[] = "*** WARNING *** Alarmp: message longer than default; dynamically allocated alarm string!\n";
+static const char Alarm_Warning_Truncate[] = "*** WARNING *** Alarmp: message longer than default and dynamic alloc failed -- alarm message truncated!\n";
+static const char Alarm_Warning_Realtime[] = "*** WARNING *** Alarmp: real time print handler failed!\n";
-static int Alarm_precise_timestamp = FALSE;
+#ifdef USE_THREADED_ALARM
+static void Threaded_Alarm_Append(const char *str, size_t str_len);
+static void Threaded_Alarm_Exit(void);
+#endif
-static const char *DEFAULT_TIMESTAMP_FORMAT="[%a %d %b %Y %H:%M:%S]";
+static int32 Alarm_type_mask = PRINT | EXIT ;
+static int16 Alarm_cur_priority = SPLOG_DEBUG ;
+static alarm_realtime_handler *Alarm_realtime_print_handler = NULL;
+
+static char *Alarm_timestamp_format = NULL;
+static int Alarm_timestamp_high_res = 0;
+
+static const char *DEFAULT_TIMESTAMP_FORMAT = "%m/%d/%y %H:%M:%S";
+/* alternate longer default timestamp "[%a %d %b %Y %H:%M:%S]"; */
+
static int AlarmInteractiveProgram = FALSE;
-#ifdef HAVE_GOOD_VARGS
+/* priority_level_active returns true if the priority level is active (i.e. should be printed)
+ * given the currently allowed priority levels.
+ */
+static bool priority_level_active( int16 priority )
+{
+ return( Alarm_cur_priority <= ( priority & SPLOG_PRIORITY_FIELDS ) );
+}
-/* Probably should work on all platforms, but just in case, I leave it to the
- developers...
-*/
+/* is_priority_set() checks whether the specific priority_to_check value is set
+ * in the 'priority' variable passed in.
+ * If value is set, then it returns true, otherwise it returns false.
+ */
+static bool is_priority_set( int16 priority, int16 priority_to_check )
+{
+ return( (priority & SPLOG_PRIORITY_FIELDS) == priority_to_check );
+}
-void Alarmp( int16 priority, int32 mask, char *message, ...)
+/* is_priority_flag_active() checks whether the specific priority_flag is set
+ * in the 'priority' variable passed in.
+ * If flag is set, then it returns true, otherwise it returns false.
+ */
+static bool is_priority_flag_active( int16 priority, int16 priority_flag )
{
+ return( (priority & SPLOG_PRIORITY_FLAGS) & priority_flag );
+}
+
+static void Output_Msg(const char *msg, int msg_len)
+{
+#ifndef USE_THREADED_ALARM
+ fwrite(msg, sizeof(char), msg_len, stdout);
+#else
+ Threaded_Alarm_Append(msg, msg_len);
+#endif
+}
+
+#ifdef HAVE_GOOD_VARGS
+
+static void Internal_Alarmp(int16 priority, int32 mask, char *message, va_list ap)
+{
/* log event if in mask and of higher priority, or if FATAL event, always log */
- if ( (( Alarm_type_mask & mask ) && (Alarm_cur_priority <= priority))
- || (priority == SPLOG_FATAL) )
- {
- va_list ap;
- if ( Alarm_timestamp_format && (priority != SPLOG_PRINT_NODATE) )
- {
- char timestamp[42];
- struct tm *tm_now;
- time_t time_now;
- size_t length;
-
- time_now = time(NULL);
- tm_now = localtime(&time_now);
- length = strftime(timestamp, 40,
- Alarm_timestamp_format, tm_now);
- timestamp[length] = ' ';
- fwrite(timestamp, length+1, sizeof(char), stdout);
- if ( Alarm_precise_timestamp )
- {
- sp_time precise_now;
- precise_now = E_get_time();
- length = sprintf (timestamp, " (%lu us): ", precise_now.usec);
- timestamp[length] = ' ';
- fwrite(timestamp, length+1, sizeof(char), stdout);
- }
+ if (((Alarm_type_mask & mask) != 0 && priority_level_active(priority)) || is_priority_set(priority, SPLOG_FATAL)) {
+
+ char buf[MAX_ALARM_MESSAGE_BUF];
+ char *alloc_buf = NULL;
+ char *tot_ptr = buf;
+ int tot_len = 0;
+ char *ts_ptr = buf;
+ int ts_len = 0;
+ char *msg_ptr = buf;
+ int msg_len = 0;
+ int tmp;
+ time_t time_now;
+ struct tm tm_now;
+ va_list ap_copy;
+ sp_time t;
+
+ if (Alarm_timestamp_format != NULL && !is_priority_flag_active(priority, SPLOG_NODATE)) {
+
+ t = E_get_time();
+ time_now = t.sec;
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&tm_now, &time_now);
+#else
+ tm_now = *localtime(&time_now); /* NOTE: not thread safe; but worst case is we get an incorrect timestamp */
+#endif
+
+ ts_len = (int) strftime(ts_ptr, MAX_ALARM_MESSAGE_BUF - 1, Alarm_timestamp_format, &tm_now); /* reserve 1 char for space appended below */
+
+ /* ensure ts_len in half open range [0, MAX_ALARM_MESSAGE_BUF - 1) */
+
+ if (ts_len >= MAX_ALARM_MESSAGE_BUF - 1) {
+ ts_len = MAX_ALARM_MESSAGE_BUF - 2;
+ }
+
+ if (ts_len < 0) {
+ ts_len = 0;
+ }
+
+ ts_ptr[ts_len] = '\0';
+
+ if (ts_len != 0) { /* strftime output successfully fit into ts_ptr; optionally append sub-second precision */
+
+ if ( Alarm_timestamp_high_res ) {
+
+ tmp = snprintf(ts_ptr + ts_len, MAX_ALARM_MESSAGE_BUF - 1 - ts_len, ".%06lu", t.usec); /* always nul terminates */
+
+ if (tmp != 7) {
+ Output_Msg(Alarm_Warning_High_Res, sizeof(Alarm_Warning_High_Res) - 1);
+ tmp = 0;
+ }
+
+ if ((ts_len += tmp) >= MAX_ALARM_MESSAGE_BUF - 1) {
+ Output_Msg(Alarm_Warning_Timestamp, sizeof(Alarm_Warning_Timestamp) - 1);
+ ts_len = MAX_ALARM_MESSAGE_BUF - 2; /* adjust ts_len to reflect snprintf truncation */
+ }
+ }
+
+ ts_ptr[ts_len] = ' '; /* append space for single alarm string */
+ ts_ptr[++ts_len] = '\0';
+
+ msg_ptr = ts_ptr + ts_len;
+ tot_len = ts_len;
+
+ } else {
+ Output_Msg(Alarm_Warning_Timestamp, sizeof(Alarm_Warning_Timestamp) - 1);
+ }
+ }
+
+ va_copy(ap_copy, ap); /* make a copy of param list in case of vsnprintf truncation */
+ msg_len = vsnprintf(msg_ptr, MAX_ALARM_MESSAGE_BUF - tot_len, message, ap);
+ tot_len += msg_len;
+
+ if (tot_len >= MAX_ALARM_MESSAGE_BUF) { /* alarm string doesn't fit in buf; dynamically allocate big enough buffer */
+
+ if ((alloc_buf = (char*) malloc(sizeof(Alarm_Warning_Alloc) - 1 + tot_len + 1)) != NULL) {
+
+ tot_ptr = alloc_buf;
+ tot_len = sizeof(Alarm_Warning_Alloc) - 1;
+ memcpy(tot_ptr, Alarm_Warning_Alloc, tot_len); /* prepend dynamic allocation warning string */
+
+ memcpy(tot_ptr + tot_len, ts_ptr, ts_len); /* copy timestamp after warning */
+ ts_ptr = tot_ptr + tot_len;
+ tot_len += ts_len;
+
+ msg_ptr = ts_ptr + ts_len;
+ tmp = vsnprintf(msg_ptr, msg_len + 1, message, ap_copy); /* write msg after timestamp */
+ assert(tmp == msg_len);
+ msg_len = tmp;
+ tot_len += msg_len;
+
+ } else { /* dynamic alloc failed; overwrite warning + truncate msg in buf */
+
+ memcpy(tot_ptr + MAX_ALARM_MESSAGE_BUF - sizeof(Alarm_Warning_Truncate), Alarm_Warning_Truncate, sizeof(Alarm_Warning_Truncate));
+ msg_len = MAX_ALARM_MESSAGE_BUF - ts_len - 1;
+ tot_len = MAX_ALARM_MESSAGE_BUF - 1;
+ tot_ptr[tot_len] = '\0';
}
+ }
- va_start(ap,message);
- vprintf(message, ap);
- va_end(ap);
+ va_end(ap_copy); /* clean up ap copy */
+
+ Output_Msg(tot_ptr, tot_len);
+
+ if (ts_len != 0) {
+ ts_ptr[--ts_len] = '\0'; /* overwrite appended space between timestamp and msg with nul terminator */
}
- if ( ( EXIT & mask ) || (priority == SPLOG_FATAL) )
- {
- printf("Exit caused by Alarm(EXIT)\n");
- exit( 0 );
- }
+ if (Alarm_realtime_print_handler != NULL &&
+ (is_priority_flag_active(priority, SPLOG_REALTIME) || is_priority_set(priority, SPLOG_FATAL))) {
+
+ tmp = Alarm_realtime_print_handler(priority, mask, ts_ptr, ts_len, msg_ptr, msg_len);
+
+ if (tmp) {
+ Output_Msg(Alarm_Warning_Realtime, sizeof(Alarm_Warning_Realtime) - 1);
+ }
+ }
+
+ if (alloc_buf != NULL) { /* clean up any dynamically allocated buffer */
+ free(alloc_buf);
+ }
+ }
+
+ if ((EXIT & mask) != 0 || is_priority_set(priority, SPLOG_FATAL)) {
+
+#ifndef USE_THREADED_ALARM
+ fprintf(stdout, "Exit caused by Alarm(EXIT)\n");
+ abort();
+ exit(0);
+#else
+ Threaded_Alarm_Exit();
+#endif
+
+ }
}
+void Alarmp( int16 priority, int32 mask, char *message, ... )
+{
+ va_list ap;
+
+ va_start(ap, message);
+ Internal_Alarmp(priority, mask, message, ap);
+ va_end(ap);
+}
+
/* For backwards compatibility while moving all Alarm calls over, this provides
* the old interface and logs them as WARNING events.
*/
-void Alarm( int32 mask, char *message, ...)
+
+void Alarm( int32 mask, char *message, ... )
{
- if ( ( Alarm_type_mask & mask ) && (Alarm_cur_priority <= SPLOG_WARNING) )
- {
- va_list ap;
+ va_list ap;
- if ( Alarm_timestamp_format )
- {
- char timestamp[42];
- struct tm *tm_now;
- time_t time_now;
- size_t length;
-
- time_now = time(NULL);
- tm_now = localtime(&time_now);
- length = strftime(timestamp, 40,
- Alarm_timestamp_format, tm_now);
- timestamp[length] = ' ';
- fwrite(timestamp, length+1, sizeof(char), stdout);
- if ( Alarm_precise_timestamp )
- {
- sp_time precise_now;
- precise_now = E_get_time();
- length = sprintf (timestamp, " (%lu us): ", precise_now.usec);
- timestamp[length] = ' ';
- fwrite(timestamp, length+1, sizeof(char), stdout);
- }
- }
+ va_start(ap, message);
+ Internal_Alarmp(SPLOG_WARNING, mask, message, ap);
+ va_end(ap);
+}
- va_start(ap,message);
- vprintf(message, ap);
- va_end(ap);
- }
-
- if ( EXIT & mask )
- {
- printf("Exit caused by Alarm(EXIT)\n");
- exit( 0 );
- }
-}
#else
-void Alarm( int16 priority, int32 mask, char *message,
- void *ptr1, void *ptr2, void *ptr3, void *ptr4,
- void *ptr5, void *ptr6, void *ptr7, void *ptr8,
- void *ptr9, void *ptr10, void*ptr11, void *ptr12,
- void *ptr13, void *ptr14, void *ptr15, void *ptr16,
- void *ptr17, void *ptr18, void *ptr19, void *ptr20)
+void Alarm( int32 mask, char *message,
+ void *ptr1, void *ptr2, void *ptr3, void *ptr4,
+ void *ptr5, void *ptr6, void *ptr7, void *ptr8,
+ void *ptr9, void *ptr10, void*ptr11, void *ptr12,
+ void *ptr13, void *ptr14, void *ptr15, void *ptr16,
+ void *ptr17, void *ptr18, void *ptr19, void *ptr20)
{
- if ( ( Alarm_type_mask & mask ) && (Alarm_cur_priority < priority) )
+ if ( ( Alarm_type_mask & mask ) && priority_level_active(SPLOG_WARNING) )
{
- if ( Alarm_timestamp_format )
+ if ( Alarm_timestamp_format != NULL )
{
char timestamp[42];
struct tm *tm_now;
time_t time_now;
size_t length;
-
- time_now = time(NULL);
- tm_now = localtime(&time_now);
- length = strftime(timestamp, 40,
- Alarm_timestamp_format, tm_now);
- timestamp[length] = ' ';
- fwrite(timestamp, length+1, sizeof(char), stdout);
- if ( Alarm_precise_timestamp )
- {
- sp_time precise_now;
- precise_now = E_get_time();
- length = sprintf (timestamp, " (%lu us): ", precise_now.usec);
- timestamp[length] = ' ';
- fwrite(timestamp, length+1, sizeof(char), stdout);
- }
+ size_t length2;
+ sp_time t = E_get_time();
+
+ time_now = t.sec;
+ tm_now = localtime(&time_now);
+ length = strftime(timestamp, sizeof(timestamp) - 1, Alarm_timestamp_format, tm_now); /* -1 reserves a char for appended ' ' below */
+
+ if (length != 0) {
+
+ if ( Alarm_timestamp_high_res && length <= sizeof(timestamp) - 1 ) {
+
+ if ((length2 = snprintf(timestamp + length, sizeof(timestamp) - 1 - length, ".%06lu", t.usec)) < sizeof(timestamp) - 1 - length) {
+ length += length2;
+ }
+ /* else attempted print will be overwritten immediately below by appending ' ' */
+ }
+
+ timestamp[length] = ' ';
+ timestamp[++length] = '\0';
+ fwrite(timestamp, sizeof(char), length, stdout);
+ timestamp[--length] = '\0';
+ }
}
- printf(message, ptr1, ptr2, ptr3, ptr4, ptr5, ptr6, ptr7, ptr8, ptr9, ptr10, ptr11, ptr12, ptr13, ptr14, ptr15, ptr16, ptr17, ptr18, ptr19, ptr20 );
+ printf(message, ptr1, ptr2, ptr3, ptr4, ptr5, ptr6, ptr7, ptr8, ptr9, ptr10, ptr11, ptr12, ptr13, ptr14, ptr15, ptr16, ptr17, ptr18, ptr19, ptr20 );
}
- if ( EXIT & mask )
- {
- printf("Exit caused by Alarm(EXIT)\n");
- exit( 0 );
- }
+ if ( EXIT & mask )
+ {
+ printf("Exit caused by Alarm(EXIT)\n");
+ abort();
+ exit( 0 );
+ }
}
#endif /* HAVE_GOOD_VARGS */
@@ -213,17 +343,8 @@
return(AlarmInteractiveProgram);
}
-void Alarm_enable_precise_timestamp(void)
+void Alarm_set_output(char *filename)
{
- Alarm_precise_timestamp = TRUE;
-}
-
-void Alarm_disable_precise_timestamp(void)
-{
- Alarm_precise_timestamp = FALSE;
-}
-
-void Alarm_set_output(char *filename) {
FILE *newfile;
newfile = freopen(filename, "a", stdout);
if ( NULL == newfile ) {
@@ -237,29 +358,66 @@
setvbuf(stdout, (char *)0, _IONBF, 0);
}
-void Alarm_enable_timestamp(char *format)
+static void Alarm_enable_timestamp_intrnl(const char *format, int high_res)
{
static char _local_timestamp[40];
- if(format)
- strncpy(_local_timestamp, format, 40);
- else
- strncpy(_local_timestamp, DEFAULT_TIMESTAMP_FORMAT, 40);
+ size_t len;
+
+ if (format) {
+ strncpy(_local_timestamp, format, sizeof(_local_timestamp) - 1);
+
+ } else {
+ strncpy(_local_timestamp, DEFAULT_TIMESTAMP_FORMAT, sizeof(_local_timestamp) - 1);
+ }
+
+ _local_timestamp[sizeof(_local_timestamp) - 1] = 0; /* ensure termination */
+
+ Alarm_timestamp_high_res = high_res;
+
+ if (high_res != 0) {
+ /* check to see if format string ends in %s or %S; if it doesn't then append " %s" to it */
+
+ len = strlen(_local_timestamp);
+
+ if (len < 2 || (strncmp(_local_timestamp + len - 2, "%s", 3) != 0 && strncmp(_local_timestamp + len - 2, "%S", 3) != 0)) {
+
+ if (sizeof(_local_timestamp) - (len + 1) >= 3) {
+ strncpy(_local_timestamp + len, " %s", 4);
+ len += 3;
+
+ } else {
+ Alarm_timestamp_high_res = 0; /* append wouldn't fit */
+ }
+ }
+ }
+
Alarm_timestamp_format = _local_timestamp;
+}
+
+void Alarm_enable_timestamp(const char *format)
+{
+ Alarm_enable_timestamp_intrnl(format, 0);
}
+void Alarm_enable_timestamp_high_res(const char *format)
+{
+ Alarm_enable_timestamp_intrnl(format, 1);
+}
+
void Alarm_disable_timestamp(void)
{
- Alarm_timestamp_format = NULL;
+ Alarm_timestamp_format = NULL;
+ Alarm_timestamp_high_res = 0;
}
void Alarm_set_types(int32 mask)
{
- Alarm_type_mask = Alarm_type_mask | mask;
+ Alarm_type_mask = Alarm_type_mask | mask;
}
void Alarm_clear_types(int32 mask)
{
- Alarm_type_mask = Alarm_type_mask & ~mask;
+ Alarm_type_mask = Alarm_type_mask & ~mask;
}
int32 Alarm_get_types(void)
@@ -269,10 +427,280 @@
void Alarm_set_priority(int16 priority)
{
- Alarm_cur_priority = priority;
+ Alarm_cur_priority = ( priority & SPLOG_PRIORITY_FIELDS );
}
int16 Alarm_get_priority(void)
{
return(Alarm_cur_priority);
}
+
+void Alarm_set_realtime_print_handler( alarm_realtime_handler *output_message_function )
+{
+ Alarm_realtime_print_handler = output_message_function;
+}
+
+#ifdef USE_THREADED_ALARM
+
+/************************************************************************************************
+ * A conditionally compiled threaded implemenation of Alarm that
+ * writes to an in-memory buffer rather than a FILE. That output is
+ * eventually written by a dedicated thread to stdout.
+ ***********************************************************************************************/
+
+#include <stdarg.h>
+#include <assert.h>
+
+#include <pthread.h>
+
+/************************************************************************************************
+ ***********************************************************************************************/
+
+#define BUFFER_VALID() (Buffer != NULL && \
+ Buffer_Lock_Offset >= 0 && Buffer_Lock_Size >= 0 && \
+ Buffer_Written_Offset >= 0 && Buffer_Written_Size >= 0 && Buffer_Wrapped_Size >= 0 && \
+ Buffer_Lock_Offset + Buffer_Lock_Size <= Buffer_Alloced && \
+ Buffer_Written_Offset == Buffer_Lock_Offset + Buffer_Lock_Size && \
+ Buffer_Written_Offset + Buffer_Written_Size <= Buffer_Alloced && \
+ Buffer_Wrapped_Size <= Buffer_Written_Offset)
+
+/************************************************************************************************
+ ***********************************************************************************************/
+
+static pthread_mutex_t Output_Mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t Output_Cond = PTHREAD_COND_INITIALIZER;
+static int Output_Thread_Running = 0; /* is Threaded_Alarm_Thread running yet? */
+
+static long Buffer_Alloced = 1048576L; /* size of circular Buffer to allocate */
+static char *Buffer = NULL; /* circular Buffer for spooling Alarm output */
+
+static long Buffer_Lock_Offset = 0; /* offset from which thread is writing */
+static long Buffer_Lock_Size = 0; /* size of thread's current write */
+
+static long Buffer_Written_Offset = 0; /* end of current Lock block */
+static long Buffer_Written_Size = 0; /* amount written past current Lock block */
+static long Buffer_Wrapped_Size = 0; /* amount written that has wrapped around */
+
+/************************************************************************************************
+ * Threaded_Alarm_Thread: Entry fcn for single, global thread to
+ * handle pushing Alarm output to a file.
+ ***********************************************************************************************/
+
+static void *Threaded_Alarm_Thread(void *dmy)
+{
+ long lock_offset;
+ size_t lock_size;
+ size_t tmp_size;
+ int tmp;
+
+ while (1) {
+
+ if ((tmp = pthread_mutex_lock(&Output_Mutex)) != 0) {
+ assert(0);
+ }
+ {
+ /* free up Lock block we just wrote for more writing */
+
+ assert(BUFFER_VALID());
+
+ Buffer_Lock_Offset += Buffer_Lock_Size;
+ Buffer_Lock_Size = 0;
+
+ assert(BUFFER_VALID());
+
+ /* wait for input */
+
+ while (Buffer_Written_Size == 0 && Buffer_Wrapped_Size == 0) {
+
+ if ((tmp = pthread_cond_wait(&Output_Cond, &Output_Mutex)) != 0) {
+ assert(0);
+ }
+
+ assert(BUFFER_VALID());
+ }
+
+ /* lock portion of Buffer to write + update variables */
+
+ if (Buffer_Written_Size != 0) { /* output waiting to be written at end of Buffer (and possibly at beginning too but ignored for now) */
+
+ Buffer_Lock_Offset = Buffer_Written_Offset;
+ Buffer_Lock_Size = Buffer_Written_Size;
+
+ Buffer_Written_Offset += Buffer_Written_Size;
+ Buffer_Written_Size = 0;
+
+ assert(BUFFER_VALID());
+
+ } else { /* output waiting to be written only at beginning of Buffer */
+
+ Buffer_Lock_Offset = 0;
+ Buffer_Lock_Size = Buffer_Wrapped_Size;
+
+ Buffer_Written_Offset = Buffer_Wrapped_Size;
+ Buffer_Written_Size = 0;
+ Buffer_Wrapped_Size = 0;
+
+ assert(BUFFER_VALID());
+ }
+
+ lock_offset = Buffer_Lock_Offset;
+ lock_size = (size_t) Buffer_Lock_Size; /* NOTE: we use local vars in case we ever use race detectors */
+
+ }
+ if ((tmp = pthread_mutex_unlock(&Output_Mutex)) != 0) {
+ assert(0);
+ }
+
+ if ((tmp_size = fwrite(Buffer + lock_offset, sizeof(char), lock_size, stdout)) < lock_size) {
+ /*assert(0);*/
+ }
+ }
+
+ assert(0);
+
+ return NULL;
+}
+
+/************************************************************************************************
+ * Threaded_Alarm_Append: Core fcn for trying to output an Alarm.
+ * Writes to an in-memory buffer that will later be pushed to disk by
+ * Alarm_Thread.
+ ***********************************************************************************************/
+
+static void Threaded_Alarm_Append(const char *str, size_t str_len)
+{
+ int try_wrap = 0;
+ int fail_print = 0;
+ char *write_here;
+ long space_left;
+ pthread_t thr;
+ int tmp;
+
+ if ((tmp = pthread_mutex_lock(&Output_Mutex)) != 0) {
+ assert(0);
+ }
+ {
+ /* ensure that Alarm_Thread is running + memory is alloc'ed */
+
+ if (!Output_Thread_Running) {
+
+ assert(Buffer_Alloced > 0);
+
+ if ((Buffer = (char*) malloc(Buffer_Alloced)) == NULL) {
+ assert(0);
+ }
+
+ if ((tmp = pthread_create(&thr, NULL, Threaded_Alarm_Thread, NULL)) != 0) {
+ assert(0);
+ }
+
+ if ((tmp = pthread_detach(thr)) != 0) {
+ assert(0);
+ }
+
+ Output_Thread_Running = 1;
+ }
+
+ /* try to append to end of Buffer */
+
+ assert(BUFFER_VALID());
+
+ if (Buffer_Wrapped_Size == 0) { /* output waiting to be written hasn't yet run off end of Buffer and wrapped around to beginning */
+
+ write_here = Buffer + Buffer_Written_Offset + Buffer_Written_Size;
+ space_left = Buffer_Alloced - (Buffer_Written_Offset + Buffer_Written_Size);
+
+ assert(space_left >= 0 && write_here >= Buffer && write_here + space_left <= Buffer + Buffer_Alloced);
+
+ if (str_len <= space_left) {
+ memcpy(write_here, str, str_len);
+ Buffer_Written_Size += (long) str_len;
+ assert(BUFFER_VALID());
+
+ } else {
+ try_wrap = 1;
+ }
+
+ } else {
+ try_wrap = 1;
+ }
+
+ /* try writing to wrap area if we didn't successfully append above */
+
+ if (try_wrap) {
+
+ write_here = Buffer + Buffer_Wrapped_Size;
+ space_left = Buffer_Lock_Offset - Buffer_Wrapped_Size;
+
+ assert(space_left >= 0 && write_here >= Buffer && write_here + space_left <= Buffer + Buffer_Lock_Offset);
+
+ if (str_len <= space_left) {
+ memcpy(write_here, str, str_len);
+ Buffer_Wrapped_Size += (long) str_len;
+ assert(BUFFER_VALID());
+
+ } else {
+ fail_print = 1;
+ }
+ }
+
+ /* signal Alarm_Thread of output to be written */
+
+ if ((tmp = pthread_cond_signal(&Output_Cond)) != 0) {
+ assert(0);
+ }
+ }
+ if ((tmp = pthread_mutex_unlock(&Output_Mutex)) != 0) {
+ assert(0);
+ }
+
+ if (fail_print) {
+ fprintf(stdout, "*** WARNING ***: Threaded_Alarm_Append: Not enough room in in-memory buffer to append Alarm msg! Writing directly to stdout!\n%s\n", str);
+ }
+}
+
+/************************************************************************************************
+ * Threaded_Alarm_Exit: Pushes out any buffered output before exiting.
+ ***********************************************************************************************/
+
+static void Threaded_Alarm_Exit(void)
+{
+ size_t tmp_size;
+ int tmp;
+
+ if ((tmp = pthread_mutex_lock(&Output_Mutex)) != 0) {
+ assert(0);
+ }
+ {
+ /* flush buffer out */
+
+ assert(BUFFER_VALID());
+
+ if (Buffer_Lock_Size != 0) { /* NOTE: might be duplicated by Threaded_Alarm_Thread -- better to duplicate than to miss though */
+
+ if ((tmp_size = fwrite(Buffer + Buffer_Lock_Offset, sizeof(char), Buffer_Lock_Size, stdout)) != Buffer_Lock_Size) {
+ assert(0);
+ }
+ }
+
+ if (Buffer_Written_Size != 0) {
+
+ if ((tmp_size = fwrite(Buffer + Buffer_Written_Offset, sizeof(char), Buffer_Written_Size, stdout)) != Buffer_Written_Size) {
+ assert(0);
+ }
+ }
+
+ if (Buffer_Wrapped_Size != 0) {
+
+ if ((tmp_size = fwrite(Buffer, sizeof(char), Buffer_Wrapped_Size, stdout)) != Buffer_Wrapped_Size) {
+ /*assert(0);*/
+ }
+ }
+
+ fprintf(stdout, "Exit caused by Alarm(EXIT)\n");
+ abort();
+ exit(0);
+ }
+}
+
+#endif /* #ifdef USE_THREADED_ALARM */
Modified: libspreadutil/trunk/src/alarm.h
===================================================================
--- libspreadutil/trunk/src/alarm.h 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/src/alarm.h 2012-01-31 05:26:05 UTC (rev 469)
@@ -39,54 +39,39 @@
#include <stdio.h>
#include "arch.h"
-#define DEBUG 0x00000001
-#define EXIT 0x00000002
-#define PRINT 0x00000004
-/* new type to replace general prints */
-#define SYSTEM 0x00000004
+/* Type for Alarm realtime handler functions */
+typedef int (alarm_realtime_handler)( int16, int32, char *, size_t, char *, size_t);
-#define DATA_LINK 0x00000010
-#define NETWORK 0x00000020
-#define PROTOCOL 0x00000040
-#define SESSION 0x00000080
-#define CONF 0x00000100
-#define MEMB 0x00000200
-#define FLOW_CONTROL 0x00000400
-#define STATUS 0x00000800
-#define EVENTS 0x00001000
-#define GROUPS 0x00002000
-#define HOP 0x00004000
-#define OBJ_HANDLER 0x00008000
-#define MEMORY 0x00010000
-#define ROUTE 0x00020000
-#define QOS 0x00040000
-#define RING 0x00080000
-#define TCP_HOP 0x00100000
+/* This includes the custom types for each project */
+#include "alarm_types.h"
-#define SKIPLIST 0x00200000
-#define ACM 0x00400000
-
-#define SECURITY 0x00800000
-
+/* These are always defined for any project using Alarm */
#define ALL 0xffffffff
#define NONE 0x00000000
-/* Priority levels */
-#define SPLOG_DEBUG 1 /* Program information that is only useful for debugging.
- Will normally be turned off in operation. */
-#define SPLOG_INFO 2 /* Program reports information that may be useful for
- performance tuning, analysis, or operational checks. */
-#define SPLOG_WARNING 3 /* Program encountered a situation that is not erroneous,
- but is uncommon and may indicate an error. */
-#define SPLOG_ERROR 4 /* Program encountered an error that can be recovered from. */
-#define SPLOG_CRITICAL 5 /* Program will not exit, but has only temporarily recovered
- and without help may soon fail. */
-#define SPLOG_FATAL 6 /* Program will exit() or abort(). */
+/* Priority levels */
+#define SPLOG_DEBUG 0x0001 /* Program information that is only useful for debugging.
+ Will normally be turned off in operation. */
+#define SPLOG_INFO 0x0002 /* Program reports information that may be useful for
+ performance tuning, analysis, or operational checks. */
+#define SPLOG_WARNING 0x0003 /* Program encountered a situation that is not erroneous,
+ but is uncommon and may indicate an error. */
+#define SPLOG_ERROR 0x0004 /* Program encountered an error that can be recovered from. */
+#define SPLOG_CRITICAL 0x0005 /* Program will not exit, but has only temporarily recovered
+ and without help may soon fail. */
+#define SPLOG_FATAL 0x0006 /* Program will exit() or abort(). */
-#define SPLOG_PRINT 7 /* Program should always print this information */
-#define SPLOG_PRINT_NODATE 8 /* Program should always print this information, but the datestamp should be omitted. */
+#define SPLOG_PRINT 0x0007 /* Program should always print this information */
+#define SPLOG_PRIORITY_FIELDS 0x000f
+
+/* Feature Flags for Priority field */
+#define SPLOG_NODATE 0x0010 /* Program should omit the datestamp at the beginning of the message. */
+#define SPLOG_REALTIME 0x0020 /* This message should be disseminated through the realtime handler if possible.
+ This is used for alerts you want sent now and not just logged (they are also logged). */
+#define SPLOG_PRIORITY_FLAGS 0x00f0
+
#ifdef HAVE_GOOD_VARGS
void Alarmp( int16 priority, int32 type, char *message, ...);
void Alarm( int32 type, char *message, ...);
@@ -97,12 +82,10 @@
void Alarm_set_output(char *filename);
-void Alarm_enable_timestamp(char *format);
+void Alarm_enable_timestamp(const char *format);
+void Alarm_enable_timestamp_high_res(const char *format);
void Alarm_disable_timestamp(void);
-void Alarm_enable_precise_timestamp(void);
-void Alarm_disable_precise_timestamp(void);
-
void Alarm_set_types(int32 mask);
void Alarm_clear_types(int32 mask);
int32 Alarm_get_types(void);
@@ -110,6 +93,8 @@
void Alarm_set_priority(int16 priority);
int16 Alarm_get_priority(void);
+void Alarm_set_realtime_print_handler( alarm_realtime_handler *output_message_function );
+
void Alarm_set_interactive(void);
int Alarm_get_interactive(void);
Added: libspreadutil/trunk/src/alarm_types.h
===================================================================
--- libspreadutil/trunk/src/alarm_types.h (rev 0)
+++ libspreadutil/trunk/src/alarm_types.h 2012-01-31 05:26:05 UTC (rev 469)
@@ -0,0 +1,84 @@
+/*
+ * The Spread Toolkit.
+ *
+ * The contents of this file are subject to the Spread Open-Source
+ * License, Version 1.0 (the ``License''); you may not use
+ * this file except in compliance with the License. You may obtain a
+ * copy of the License at:
+ *
+ * http://www.spread.org/license/
+ *
+ * or in the file ``license.txt'' found in this distribution.
+ *
+ * Software distributed under the License is distributed on an AS IS basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Creators of Spread are:
+ * Yair Amir, Michal Miskin-Amir, Jonathan Stanton, John Schultz.
+ *
+ * Copyright (C) 1993-2006 Spread Concepts LLC <info at spreadconcepts.com>
+ *
+ * All Rights Reserved.
+ *
+ * Major Contributor(s):
+ * ---------------
+ * Ryan Caudy rcaudy at gmail.com - contributions to process groups.
+ * Cristina Nita-Rotaru crisn at cs.purdue.edu - group communication security.
+ * Theo Schlossnagle jesus at omniti.com - Perl, autoconf, old skiplist.
+ * Dan Schoenblum dansch at cnds.jhu.edu - Java interface.
+ *
+ *
+ * This file is also licensed by Spread Concepts LLC under the Spines
+ * Open-Source License, version 1.0. You may obtain a copy of the
+ * Spines Open-Source License, version 1.0 at:
+ *
+ * http://www.spines.org/LICENSE.txt
+ *
+ * or in the file ``LICENSE.txt'' found in this distribution.
+ *
+ */
+
+
+#ifndef INC_ALARM_TYPES
+#define INC_ALARM_TYPES
+
+#include "arch.h"
+
+/* List of type values that are valid for this project.
+ * This list can be customized for each user of Alarm library.
+ * The defines must be consistent amoung all code that will be compiled together,
+ * but can be different for different executables
+ */
+#define DEBUG 0x00000001
+#define EXIT 0x00000002
+#define PRINT 0x00000004
+/* new type to replace general prints */
+#define SYSTEM 0x00000004
+
+#define DATA_LINK 0x00000010
+#define NETWORK 0x00000020
+#define PROTOCOL 0x00000040
+#define SESSION 0x00000080
+//#define CONF 0x00000100 Clash with an OpenSSL definition
+#define MEMB 0x00000200
+#define FLOW_CONTROL 0x00000400
+#define STATUS 0x00000800
+#define EVENTS 0x00001000
+#define GROUPS 0x00002000
+
+#define HOP 0x00004000
+#define OBJ_HANDLER 0x00008000
+#define MEMORY 0x00010000
+#define ROUTE 0x00020000
+#define QOS 0x00040000
+#define RING 0x00080000
+#define TCP_HOP 0x00100000
+
+#define SKIPLIST 0x00200000
+#define ACM 0x00400000
+
+#define SECURITY 0x00800000
+
+#endif /* INC_ALARM_TYPES */
Added: libspreadutil/trunk/src/arch.c
===================================================================
--- libspreadutil/trunk/src/arch.c (rev 0)
+++ libspreadutil/trunk/src/arch.c 2012-01-31 05:26:05 UTC (rev 469)
@@ -0,0 +1,109 @@
+/*
+ * The Spread Toolkit.
+ *
+ * The contents of this file are subject to the Spread Open-Source
+ * License, Version 1.0 (the ``License''); you may not use
+ * this file except in compliance with the License. You may obtain a
+ * copy of the License at:
+ *
+ * http://www.spread.org/license/
+ *
+ * or in the file ``license.txt'' found in this distribution.
+ *
+ * Software distributed under the License is distributed on an AS IS basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Creators of Spread are:
+ * Yair Amir, Michal Miskin-Amir, Jonathan Stanton, John Schultz.
+ *
+ * Copyright (C) 1993-2006 Spread Concepts LLC <info at spreadconcepts.com>
+ *
+ * All Rights Reserved.
+ *
+ * Major Contributor(s):
+ * ---------------
+ * Ryan Caudy rcaudy at gmail.com - contributions to process groups.
+ * Claudiu Danilov claudiu at acm.org - scalable wide area support.
+ * Cristina Nita-Rotaru crisn at cs.purdue.edu - group communication security.
+ * Theo Schlossnagle jesus at omniti.com - Perl, autoconf, old skiplist.
+ * Dan Schoenblum dansch at cnds.jhu.edu - Java interface.
+ *
+ */
+
+
+#include "arch.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef ARCH_PC_WIN95
+#include <winsock.h>
+#endif
+
+#ifndef HAVE_STRERROR
+/* return value only valid until next call to strerror */
+
+char *strerror(int err)
+{
+ char *msg;
+static char buf[32];
+
+ sprintf(buf, "Error %d", err);
+ msg = buf;
+
+ return(msg);
+}
+
+#endif
+
+#ifdef ARCH_PC_WIN95
+/* return value only valid until next call to sock_strerror */
+
+char *sock_strerror(int err)
+{
+ switch( err ) {
+ case WSANOTINITIALISED:
+ return "WSANOTINITIALISED: A successful WSAStartup() must occur before using this function.";
+ case WSAENETDOWN:
+ return "WSAENETDOWN: The network subsystem has failed.";
+ case WSAEACCES:
+ return "WSAEACCES: The requested address is a broadcast address, but the appropriate flag was not set. Call setsockopt with the SO_BROADCAST parameter to allow the use of the broadcast address.";
+ case WSAEINTR:
+ return "WSAEINTR: A blocking Windows Sockets 1.1 call was canceled through WSACancelBlockingCall.";
+ case WSAEINPROGRESS:
+ return "WSAEINPROGRESS: A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.";
+ case WSAEFAULT:
+ return "WSAEFAULT: The buf parameter is not completely contained in a valid part of the user address space." ;
+ case WSAENETRESET:
+ return "WSAENETRESET: The connection has been broken due to the keep-alive activity detecting a failure while the operation was in progress.";
+ case WSAENOBUFS:
+ return "WSAENOBUFS: No buffer space is available.";
+ case WSAENOTCONN:
+ return "WSAENOTCONN: The socket is not connected.";
+ case WSAENOTSOCK:
+ return "WSAENOTSOCK: The descriptor is not a socket.";
+ case WSAEOPNOTSUPP:
+ return "WSAEOPNOTSUPP: MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, out-of-band data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only receive operations.";
+ case WSAESHUTDOWN:
+ return "WSAESHUTDOWN The socket has been shut down; it is not possible to send on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH.";
+ case WSAEWOULDBLOCK:
+ return "WSAEWOULDBLOCK: The socket is marked as nonblocking and the requested operation would block.";
+ case WSAEMSGSIZE:
+ return "WSAEMSGSIZE: The socket is message oriented, and the message is larger than the maximum supported by the underlying transport.";
+ case WSAEHOSTUNREACH:
+ return "WSAEHOSTUNREACH: The remote host cannot be reached from this host at this time.";
+ case WSAEINVAL:
+ return "WSAEINVAL: The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled.";
+ case WSAECONNABORTED:
+ return "WSAECONNABORTED: The virtual circuit was terminated due to a time-out or other failure. The application should close the socket as it is no longer usable.";
+ case WSAECONNRESET:
+ return "WSAECONNRESET: The virtual circuit was reset by the remote side executing a hard or abortive close. For UPD sockets, the remote host was unable to deliver a previously sent UDP datagram and responded with a Port Unreachable ICMP packet. The application should close the socket as it is no longer usable.";
+ case WSAETIMEDOUT:
+ return "WSAETIMEDOUT: The connection has been dropped, because of a network failure or because the system on the other end went down without notice.";
+ default:
+ return "Unknown WSA error!";
+ }
+}
+
+#endif
Modified: libspreadutil/trunk/src/arch.h
===================================================================
--- libspreadutil/trunk/src/arch.h 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/src/arch.h 2012-01-31 05:26:05 UTC (rev 469)
@@ -158,10 +158,12 @@
#undef EAGAIN
#undef EWOULDBLOCK
#undef EINPROGRESS
+#undef EALREADY
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EINTR WSAEINTR
#define EAGAIN WSAEWOULDBLOCK
#define EINPROGRESS WSAEINPROGRESS
+#define EALREADY WSAEALREADY
/* Windows does not define MAXHOSTNAMELEN, so we define it here to a reasonable host name limit */
#define MAXHOSTNAMELEN 128
@@ -174,7 +176,7 @@
#ifndef int16
#define int16 short
-char *soch_strerror(int err); /* forward declare this func from the arch.c file (win32 only) */
+char *sock_strerror(int err); /* forward declare this func from the arch.c file (win32 only) */
#endif
@@ -197,6 +199,13 @@
#define INT32_MAX INT_MAX
#endif
+#ifndef int64_t
+#define int64_t __int64
+#endif
+
+#define PRId64 "I64d"
+
+
/* Declare functions from arch.c */
char *sock_strerror(int err);
@@ -221,10 +230,23 @@
#define Same_endian( type ) ( ( (type) & ENDIAN_TYPE ) == ARCH_ENDIAN )
#define Clear_endian( type ) ( (type) & ~ENDIAN_TYPE )
+#ifndef Flip_int16
#define Flip_int16( type ) ( ( ((type) >> 8) & 0x00ff) | ( ((type) << 8) & 0xff00) )
+#endif
+#ifndef Flip_int32
#define Flip_int32( type ) ( ( ((type) >>24) & 0x000000ff) | ( ((type) >> 8) & 0x0000ff00) | ( ((type) << 8) & 0x00ff0000) | ( ((type) <<24) & 0xff000000) )
+#endif
+#ifndef Flip_int64
+#define Flip_int64( type ) ( \
+ (((type) & ((int64_t) 0xff << 0)) << 56) | (((type) & ((int64_t) 0xff << 8)) << 40) | \
+ (((type) & ((int64_t) 0xff << 16)) << 24) | (((type) & ((int64_t) 0xff << 24)) << 8) | \
+ (((type) & ((int64_t) 0xff << 32)) >> 8) | (((type) & ((int64_t) 0xff << 40)) >> 24) | \
+ (((type) & ((int64_t) 0xff << 48)) >> 40) | (((type) & ((int64_t) 0xff << 56)) >> 56) )
+#endif
+
+
#define channel int
#define mailbox int
@@ -243,8 +265,14 @@
*/
#ifndef __cplusplus
+/*
+ * May want to just undef it as shown below. Test to see what we want.
+ * work around bad/different bool definitions in system headers
+ * #undef bool
+ */
typedef short bool;
#endif
+
#ifndef TRUE
#define TRUE 1
#endif
Modified: libspreadutil/trunk/src/data_link.c
===================================================================
--- libspreadutil/trunk/src/data_link.c 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/src/data_link.c 2012-01-31 05:26:05 UTC (rev 469)
@@ -64,7 +64,7 @@
{
channel chan;
struct sockaddr_in soc_addr;
- int on=1;
+ int on=1, off=0;
#ifdef IP_MULTICAST_TTL
unsigned char ttl_val;
#endif
@@ -100,14 +100,27 @@
#ifdef HAVE_SIN_LEN_IN_STRUCT_SOCKADDR_IN
soc_addr.sin_len = sizeof(soc_addr);
#endif
- if (interface_address == 0)
+
+ /* If mcast channel, the interface means the interface to
+ receive mcast packets on, and not interface to bind.
+ Must bind multicast address instead */
+ if (mcast_address != 0)
+ soc_addr.sin_addr.s_addr= htonl(mcast_address);
+ else if (interface_address != 0)
+ soc_addr.sin_addr.s_addr= htonl(interface_address);
+ else
soc_addr.sin_addr.s_addr= INADDR_ANY;
- else
- soc_addr.sin_addr.s_addr= htonl(interface_address);
+ /* Older Version
+ if (interface_address == 0)
+ soc_addr.sin_addr.s_addr= INADDR_ANY;
+ else
+ soc_addr.sin_addr.s_addr= htonl(interface_address);
+ */
+
if ( channel_type & REUSE_ADDR )
{
- if(setsockopt(chan, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)) < 0)
+ if(setsockopt(chan, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)))
{
Alarm( EXIT, "DL_init_channel: Failed to set socket option REUSEADDR, errno: %d\n", errno);
}
@@ -130,14 +143,26 @@
mreq.imr_multiaddr.s_addr = htonl( mcast_address );
/* the interface could be changed to a specific interface if needed */
- mreq.imr_interface.s_addr = INADDR_ANY;
-
+ /* WAS: mreq.imr_interface.s_addr = INADDR_ANY;
+ * If specified, then want to route through it instead of
+ * based on routing decisions at the kernel */
+ mreq.imr_interface.s_addr = htonl( interface_address );
+
if (setsockopt(chan, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq,
sizeof(mreq)) < 0)
{
Alarm( EXIT, "DL_init_channel: problem in setsockopt to multicast address " IPF "\n", IP(mcast_address) );
}
+ if ( channel_type & NO_LOOP )
+ {
+ if (setsockopt(chan, IPPROTO_IP, IP_MULTICAST_LOOP,
+ (void *)&off, 1) < 0)
+ {
+ Alarm( EXIT, "DL_init_channel: problem in setsockopt loop setting " IPF "\n", IP(mcast_address));
+ }
+ }
+
Alarm( DATA_LINK, "DL_init_channel: Joining multicast address " IPF " went ok\n", IP(mcast_address) );
#else /* no multicast support */
Alarm( EXIT, "DL_init_channel: Old SunOS architecture does not support IP multicast: " IPF "\n", IP(mcast_address));
@@ -339,8 +364,13 @@
else if (ret == 0)
{
char *sptr;
- sptr = (char *) inet_ntoa(source_address.sin_addr);
- Alarm( DATA_LINK, "DL_recv: received zero length packet on channel %d flags 0x%x\nfrom %s", chan, msg.msg_flags,sptr );
+ unsigned short port;
+ Alarm( DATA_LINK, "DL_recv: received zero length packet on channel %d flags 0x%x msg_len %d\n", chan, msg.msg_flags, msg.msg_namelen);
+ if (msg.msg_namelen >= sizeof(struct sockaddr_in) ) {
+ sptr = (char *) inet_ntoa(source_address.sin_addr);
+ port = Flip_int16(source_address.sin_port);
+ Alarm( DATA_LINK, "\tfrom %s with family %d port %d\n", sptr, source_address.sin_family, port );
+ }
#ifdef MSG_BCAST
if ( msg.msg_flags & MSG_BCAST )
{
Modified: libspreadutil/trunk/src/data_link.h
===================================================================
--- libspreadutil/trunk/src/data_link.h 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/src/data_link.h 2012-01-31 05:26:05 UTC (rev 469)
@@ -43,7 +43,7 @@
#define SEND_CHANNEL 0x00000001
#define RECV_CHANNEL 0x00000002
-#define RESERVED 0x00000004
+#define NO_LOOP 0x00000004
#define REUSE_ADDR 0x00000008
#define IS_MCAST_ADDR(addr) ( ( (addr) & 0xF0000000 ) == 0xE0000000 )
Modified: libspreadutil/trunk/src/events.c
===================================================================
--- libspreadutil/trunk/src/events.c 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/src/events.c 2012-01-31 05:26:05 UTC (rev 469)
@@ -33,6 +33,9 @@
*/
+/* Must come before any system headers as otherwise it is ignored */
+#define _GNU_SOURCE
+
#include "arch.h"
/* undef redefined variables under windows */
@@ -42,6 +45,7 @@
#undef EWOULDBLOCK
#undef EINPROGRESS
#endif
+
#include <errno.h>
#ifndef ARCH_PC_WIN95
@@ -50,6 +54,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
+#include <dlfcn.h>
#else /* ARCH_PC_WIN95 */
#include <winsock.h>
@@ -96,6 +101,26 @@
static int Active_priority;
static int Exit_events;
+enum ev_type {
+ NULL_EVENT_t = 0,
+ TIME_EVENT_t,
+ FD_EVENT_t,
+};
+
+#define EVENT_RECORD_NAMELEN 128
+
+struct event_record {
+ sp_time dur;
+ enum ev_type type;
+ char funcname[EVENT_RECORD_NAMELEN];
+ fd_event fev;
+ time_event tev;
+};
+
+int Slow_events_max = 5;
+int Slow_events_active = 0;
+static struct event_record Slow_events[5];
+
int E_init(void)
{
int i,ret;
@@ -355,6 +380,45 @@
return( -1 );
}
+int E_in_queue( void (* func)( int code, void *data ), int code,
+ void *data )
+{
+ time_event *t_pre;
+ time_event *t_ptr;
+
+ if( Time_queue == NULL )
+ {
+ Alarm( EVENTS, "E_in_queue: no such event\n" );
+ return( 0 );
+ }
+
+ if( Time_queue->func == func &&
+ Time_queue->data == data &&
+ Time_queue->code == code )
+ {
+ Alarm( EVENTS, "E_in_queue: found event in queue func 0x%x code %d data 0x%x\n",func,code, data);
+ return( 1 );
+ }
+
+ t_pre = Time_queue;
+ while ( t_pre->next != NULL )
+ {
+ t_ptr = t_pre->next;
+ if( t_ptr->func == func &&
+ t_ptr->data == data &&
+ t_ptr->code == code )
+ {
+ Alarm( EVENTS, "E_in_queue: found event in queue func 0x%x code %d data 0x%x\n",func,code, data);
+ return(1);
+ }
+ t_pre = t_ptr;
+ }
+
+ Alarm( EVENTS, "E_in_queue: no such event\n" );
+ return( 0 );
+}
+
+
void E_delay( sp_time t )
{
struct timeval tmp_t;
@@ -372,7 +436,113 @@
#endif /* ARCH_PC_WIN95 */
}
-
+
+
+void E_print_slow_event( struct event_record *ev )
+{
+
+ if (ev->type == NULL_EVENT_t)
+ return;
+
+ Alarmp( SPLOG_PRINT, SYSTEM, "Slow Event: %s \ttook %d.%06d sec:", &ev->funcname[0], ev->dur.sec, ev->dur.usec);
+ if (ev->type == FD_EVENT_t)
+ Alarmp( SPLOG_PRINT | SPLOG_NODATE, SYSTEM, "fd event: fd (%d) type (%d) funcptr (0x%x) code (%d) data ptr (0x%x) active (%d)\n", ev->fev.fd, ev->fev.fd_type, ev->fev.func, ev->fev.code, ev->fev.data, ev->fev.active);
+ if (ev->type == TIME_EVENT_t)
+ Alarmp( SPLOG_PRINT | SPLOG_NODATE, SYSTEM, "time event: funcptr (0x%x) code (%d) data ptr (0x%x)\n", ev->tev.func, ev->tev.code, ev->tev.data);
+
+ return;
+}
+
+void E_print_slow_events(void)
+{
+ int i;
+
+ for ( i = 0; i < Slow_events_active; i++ ) {
+ E_print_slow_event( &Slow_events[i] );
+ }
+
+}
+
+void E_lookup_function_name( void* fptr, char *fname, int fname_len )
+{
+ Dl_info dli;
+ int ret, len;
+
+ ret = dladdr(fptr, &dli);
+
+ if (ret == 0) {
+ /* Failed call */
+ len = snprintf( fname, fname_len -1, "LOOKUP_FAIL_0x%p", fptr);
+ /* NOTE: snprintf is safe if fname is too short, the string will be truncated and null terminated */
+ } else {
+ if (dli.dli_sname == NULL) {
+ len = snprintf( fname, fname_len -1, "NO_NAME");
+ } else {
+ len = strlen(dli.dli_sname);
+ strncpy( fname, dli.dli_sname, fname_len - 1);
+ if (len >= fname_len) {
+ /* function name too long to store, so truncate it */
+ fname[fname_len -1] = '\0';
+ }
+ }
+ }
+ return;
+}
+
+void E_time_events( sp_time start, sp_time stop, fd_event *fev, time_event *tev)
+{
+ sp_time ev_dur;
+ int slot,i;
+
+
+ if ( (fev != NULL && tev != NULL) || (fev == NULL && tev == NULL) ) {
+ Alarm( EXIT, "E_time_events: Bug! called with invalid fev (0x%x) and tev (0x%x) pointers. Exactly one must be non NULL\n", fev, tev);
+ }
+
+ ev_dur = E_sub_time( stop, start );
+ if ( Slow_events_active != 0 && E_compare_time( ev_dur, Slow_events[Slow_events_active-1].dur) <= 0 ) {
+ /* Fast event so skip */
+ return;
+ } else {
+ if ( Slow_events_active == 0 ) {
+ slot = 0;
+ } else {
+ /* this event is slower then at least one current slow_events so it gets added */
+ slot = Slow_events_active -1;
+ i = slot -1;
+ while (i >= 0 && E_compare_time( ev_dur, Slow_events[i].dur) > 0) {
+ slot=i;
+ i--;
+ }
+ }
+ /* slot is now the slot holding the new location of this slow event. */
+ Alarmp( SPLOG_DEBUG, SYSTEM, "DEBUG: Currently %d events stored -- Insert slow event (dur %d.%06d) into slot %d. Prev duration %d.%06d\n", Slow_events_active, ev_dur.sec, ev_dur.usec, slot, Slow_events[slot].dur.sec, Slow_events[slot].dur.usec);
+
+ if (slot < Slow_events_max -1)
+ memmove( &Slow_events[slot+1], &Slow_events[slot], (Slow_events_max - slot - 1) * sizeof(struct event_record));
+ Slow_events[slot].dur = ev_dur;
+ if (fev == NULL) {
+ Slow_events[slot].type = TIME_EVENT_t;
+ E_lookup_function_name( tev->func, &Slow_events[slot].funcname[0], EVENT_RECORD_NAMELEN);
+ Slow_events[slot].tev = *tev;
+ } else if (tev == NULL) {
+ Slow_events[slot].type = FD_EVENT_t;
+ E_lookup_function_name( fev->func, &Slow_events[slot].funcname[0], EVENT_RECORD_NAMELEN);
+ Slow_events[slot].fev = *fev;
+ }
+
+
+ if (Slow_events_active < Slow_events_max)
+ Slow_events_active++;
+
+ /* Debug print all events */
+ /* E_print_slow_events(); */
+ }
+
+ return;
+}
+
+
int E_attach_fd( int fd, int fd_type,
void (* func)( mailbox mbox, int code, void *data ),
int code, void *data, int priority )
@@ -596,6 +766,7 @@
fd_set current_mask[NUM_FDTYPES];
time_event *temp_ptr;
int first=1;
+ sp_time ev_start;
#ifdef TESTTIME
sp_time tmp_late,start,stop,req_time; /* DEBUGGING */
#endif
@@ -633,6 +804,7 @@
#ifdef TESTTIME
Alarm( DEBUG, "Events: TimeEv is %d %d late\n",tmp_late.sec, tmp_late.usec);
#endif
+ ev_start = Now;
temp_ptr->func( temp_ptr->code, temp_ptr->data );
dispose( temp_ptr );
#ifdef BADCLOCK
@@ -641,6 +813,8 @@
#else
E_get_time_monotonic();
#endif
+ E_time_events( ev_start, Now, NULL, temp_ptr );
+
if (Exit_events) goto end_handler;
}else{
timeout = E_sub_time( Time_queue->t, Now );
@@ -704,6 +878,13 @@
{
Alarm( EVENTS, "E_handle_events: exec handler for fd %d, fd_type %d, priority %d\n",
fd, fd_type, i );
+#ifdef BADCLOCK
+ Now = E_add_time( Now, mili_sec );
+ clock_sync++;
+#else
+ E_get_time_monotonic();
+#endif
+ ev_start = Now;
Fd_queue[i].events[j].func(
Fd_queue[i].events[j].fd,
Fd_queue[i].events[j].code,
@@ -716,6 +897,8 @@
#else
E_get_time_monotonic();
#endif
+ E_time_events(ev_start, Now, &(Fd_queue[i].events[j]), NULL);
+
if (Exit_events) goto end_handler;
}
}
@@ -751,6 +934,13 @@
Round_robin = ( j + 1 ) % Fd_queue[LOW_PRIORITY].num_fds;
Alarm( EVENTS , "E_handle_events: exec ext fd event \n");
+#ifdef BADCLOCK
+ Now = E_add_time( Now, mili_sec );
+ clock_sync++;
+#else
+ E_get_time_monotonic();
+#endif
+ ev_start = Now;
Fd_queue[LOW_PRIORITY].events[j].func(
Fd_queue[LOW_PRIORITY].events[j].fd,
Fd_queue[LOW_PRIORITY].events[j].code,
@@ -762,6 +952,9 @@
#else
E_get_time_monotonic();
#endif
+
+ E_time_events(ev_start, Now, &(Fd_queue[LOW_PRIORITY].events[j]), NULL);
+
if (Exit_events) goto end_handler;
break;
}
Modified: libspreadutil/trunk/src/memory.c
===================================================================
--- libspreadutil/trunk/src/memory.c 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/src/memory.c 2012-01-31 05:26:05 UTC (rev 469)
@@ -48,6 +48,7 @@
#include "alarm.h"
#include "objects.h"
+#define NO_REF_CNT -1
#define MAX_MEM_OBJECTS 200
/* Define SPREAD_STATUS when Memory is compiled with the Spread Status system.
@@ -80,6 +81,7 @@
typedef struct mem_header_d
{
int32u obj_type;
+ int32 ref_cnt;
size_t block_len;
} mem_header;
@@ -308,6 +310,10 @@
assert(threshold == 0);
assert(initial == 0);
}
+
+#ifndef NDEBUG
+ threshold = 0; /* TODO: for valgrinding only; delete me */
+#endif
Mem[obj_type].exist = TRUE;
Mem[obj_type].size = size;
@@ -344,6 +350,7 @@
head_ptr->obj_type = obj_type;
head_ptr->block_len = sizeobj(obj_type);
+ head_ptr->ref_cnt = NO_REF_CNT;
/* We add 1 because pointer arithm. states a pointer + 1 equals a pointer
* to the next element in an array where each element is of a particular size.
* in this case that size is 8 (or 12)
@@ -363,6 +370,8 @@
printf("size head = %u\t size body = %u\n", sizeof(mem_header), sizeobj(obj_type));
#endif
+ /* TODO: we should store the link to next in mem_header_ptr(object) rather than in body bc object might be less than sizeof(void*) in size */
+
*body_ptr = (void *) Mem[obj_type].list_head;
Mem[obj_type].list_head = body_ptr;
Mem[obj_type].num_obj_inpool++;
@@ -442,11 +451,18 @@
}
head_ptr->obj_type = obj_type;
head_ptr->block_len = sizeobj(obj_type);
+ head_ptr->ref_cnt = NO_REF_CNT;
#ifndef NDEBUG
+ assert(Mem[obj_type].num_obj + 1 > Mem[obj_type].num_obj);
Mem[obj_type].num_obj++;
+
+ assert(Mem[obj_type].num_obj_inuse + 1 > Mem[obj_type].num_obj_inuse);
Mem[obj_type].num_obj_inuse++;
+
+ assert(Mem[obj_type].bytes_allocated + (sizeobj(obj_type) + sizeof(mem_header)) > Mem[obj_type].bytes_allocated);
Mem[obj_type].bytes_allocated += (sizeobj(obj_type) + sizeof(mem_header));
+
if (Mem[obj_type].bytes_allocated > Mem[obj_type].max_bytes)
{
Mem[obj_type].max_bytes = Mem[obj_type].bytes_allocated;
@@ -460,9 +476,15 @@
Mem[obj_type].max_obj_inuse = Mem[obj_type].num_obj_inuse;
}
+ assert(Mem_Bytes_Allocated + (sizeobj(obj_type) + sizeof(mem_header)) > Mem_Bytes_Allocated);
Mem_Bytes_Allocated += (sizeobj(obj_type) + sizeof(mem_header));
+
+ assert(Mem_Obj_Allocated + 1 > Mem_Obj_Allocated);
Mem_Obj_Allocated++;
+
+ assert(Mem_Obj_Inuse + 1 > Mem_Obj_Inuse);
Mem_Obj_Inuse++;
+
if (Mem_Bytes_Allocated > Mem_Max_Bytes)
{
Mem_Max_Bytes = Mem_Bytes_Allocated;
@@ -488,6 +510,8 @@
return((void *) (head_ptr + 1));
} else
{
+ /* TODO: we should store the link to next in mem_header_ptr(object) rather than in body bc object might be less than sizeof(void*) in size */
+
void ** body_ptr;
assert(Mem[obj_type].num_obj_inpool > 0 );
@@ -495,12 +519,17 @@
Mem[obj_type].list_head = (void *) *(body_ptr);
Mem[obj_type].num_obj_inpool--;
#ifndef NDEBUG
+ assert(Mem[obj_type].num_obj_inuse + 1 > Mem[obj_type].num_obj_inuse);
Mem[obj_type].num_obj_inuse++;
+
if (Mem[obj_type].num_obj_inuse > Mem[obj_type].max_obj_inuse)
{
Mem[obj_type].max_obj_inuse = Mem[obj_type].num_obj_inuse;
}
+
+ assert(Mem_Obj_Inuse + 1 > Mem_Obj_Inuse);
Mem_Obj_Inuse++;
+
if (Mem_Obj_Inuse > Mem_Max_Obj_Inuse)
{
Mem_Max_Obj_Inuse = Mem_Obj_Inuse;
@@ -545,12 +574,19 @@
}
head_ptr->obj_type = BLOCK_OBJECT;
head_ptr->block_len = length;
+ head_ptr->ref_cnt = NO_REF_CNT;
#ifndef NDEBUG
+ assert(Mem[BLOCK_OBJECT].num_obj + 1 > Mem[BLOCK_OBJECT].num_obj);
Mem[BLOCK_OBJECT].num_obj++;
+
+ assert(Mem[BLOCK_OBJECT].num_obj_inuse + 1 > Mem[BLOCK_OBJECT].num_obj_inuse);
Mem[BLOCK_OBJECT].num_obj_inuse++;
+
+ assert(Mem[BLOCK_OBJECT].bytes_allocated + (length + sizeof(mem_header)) > Mem[BLOCK_OBJECT].bytes_allocated);
Mem[BLOCK_OBJECT].bytes_allocated += (length + sizeof(mem_header));
+
if (Mem[BLOCK_OBJECT].bytes_allocated > Mem[BLOCK_OBJECT].max_bytes)
{
Mem[BLOCK_OBJECT].max_bytes = Mem[BLOCK_OBJECT].bytes_allocated;
@@ -564,9 +600,15 @@
Mem[BLOCK_OBJECT].max_obj_inuse = Mem[BLOCK_OBJECT].num_obj_inuse;
}
+ assert(Mem_Bytes_Allocated + (length + sizeof(mem_header)) > Mem_Bytes_Allocated);
Mem_Bytes_Allocated += (length + sizeof(mem_header));
+
+ assert(Mem_Obj_Allocated + 1 > Mem_Obj_Allocated);
Mem_Obj_Allocated++;
+
+ assert(Mem_Obj_Inuse + 1 > Mem_Obj_Inuse);
Mem_Obj_Inuse++;
+
if (Mem_Bytes_Allocated > Mem_Max_Bytes)
{
Mem_Max_Bytes = Mem_Bytes_Allocated;
@@ -592,21 +634,30 @@
void dispose(void *object)
{
int32u obj_type;
+ int32 ref_cnt;
if (object == NULL) { return; }
obj_type = mem_header_ptr(object)->obj_type;
+ ref_cnt = mem_header_ptr(object)->ref_cnt;
+
#ifdef TESTING
printf("disp:object = 0x%x\n", object);
printf("disp:mem_headerptr = 0x%x\n", mem_header_ptr(object));
printf("disp:objtype = %u:\n", mem_header_ptr(object)->obj_type);
printf("disp:blocklen = %u:\n", mem_header_ptr(object)->block_len);
#endif
+
assert(Mem_valid_objtype(obj_type));
+ assert(ref_cnt == NO_REF_CNT);
+
#ifndef NDEBUG
assert(Mem[obj_type].num_obj_inuse > 0);
assert(Mem[obj_type].num_obj > 0);
- assert(Mem[obj_type].bytes_allocated >= mem_header_ptr(object)->block_len + sizeof(mem_header));
+ assert(Mem[obj_type].bytes_allocated >= (mem_header_ptr(object)->block_len + sizeof(mem_header)));
+ assert(Mem_Obj_Inuse > 0);
+ assert(Mem_Obj_Allocated > 0);
+ assert(Mem_Bytes_Allocated >= (mem_header_ptr(object)->block_len + sizeof(mem_header)));
Alarm(MEMORY, "dispose: disposing pointer 0x%x to object type %d named %s\n", object, obj_type, Objnum_to_String(obj_type));
@@ -623,9 +674,9 @@
{
#ifndef NDEBUG
Mem[obj_type].num_obj--;
- Mem[obj_type].bytes_allocated -= (sizeobj(obj_type) + sizeof(mem_header));
+ Mem[obj_type].bytes_allocated -= (mem_header_ptr(object)->block_len + sizeof(mem_header));
Mem_Obj_Allocated--;
- Mem_Bytes_Allocated -= (sizeobj(obj_type) + sizeof(mem_header));
+ Mem_Bytes_Allocated -= (mem_header_ptr(object)->block_len + sizeof(mem_header));
#endif
free(mem_header_ptr(object));
@@ -633,9 +684,12 @@
{
void ** body_ptr;
+ /* TODO: we should store the link to next in mem_header_ptr(object) rather than in body bc object might be less than sizeof(void*) in size */
+
body_ptr = (void **) object;
*body_ptr = (void *) Mem[obj_type].list_head;
Mem[obj_type].list_head = body_ptr;
+ assert(Mem[obj_type].num_obj_inpool + 1 > Mem[obj_type].num_obj_inpool);
Mem[obj_type].num_obj_inpool++;
}
}
@@ -685,10 +739,90 @@
}
-#if ( SPREAD_PROTOCOL == 3 )
+/* Input: a size of memory block desired
+ * Output: a pointer to memory which will hold the block
+ * Effects:
+ */
+void * Mem_alloc_ref_cnt(unsigned int length)
+{
+ void * object;
+
+ if ((object = Mem_alloc(length)) != NULL) {
+ mem_header_ptr(object)->ref_cnt = 1;
+ }
+
+ return(object);
+}
+
+/* Input: a valid type of object
+ * Output: a pointer to memory which will hold an object
+ * Effects: will only allocate an object from system if none exist in pool
+ * The allocated object will have reference counter initiated with 1
+ */
+void* new_ref_cnt(int32 obj_type)
+{
+ void *object;
+
+ if((object = new(obj_type)) != NULL) {
+ mem_header_ptr(object)->ref_cnt = 1;
+ }
+
+ return(object);
+}
+
+/* Input: a valid pointer to a reference count object
+ * Output: the resulting reference count
+ * Effects: Increments the reference count of an object
+ */
+int inc_ref_cnt(void *object)
+{
+ assert(object != NULL);
+ assert(mem_header_ptr(object)->ref_cnt > 0);
+ return(++mem_header_ptr(object)->ref_cnt);
+}
+
+
+/* Input: a valid pointer to a reference count object
+ * Output: the resulting reference count
+ * Effects: Decrements the reference count of an object.
+ * If the resulting reference count is 0, then the object is disposed
+ */
+int dec_ref_cnt(void *object)
+{
+ int ret;
+
+ if(object == NULL) { return 0; }
+
+ assert(mem_header_ptr(object)->ref_cnt > 0);
+ ret = --mem_header_ptr(object)->ref_cnt;
+
+ if(ret == 0) {
+ mem_header_ptr(object)->ref_cnt = NO_REF_CNT;
+ dispose(object);
+ }
+ return(ret);
+}
+
+
+
+/* Input: a valid pointer to a reference count object
+ * Output: the reference count of the object
+ * Effects: Returns the reference count of an object.
+ */
+int get_ref_cnt(void *object)
+{
+ if(object == NULL) { return 0; }
+
+ assert(mem_header_ptr(object)->ref_cnt > 0);
+ return(mem_header_ptr(object)->ref_cnt);
+}
+
+
char *Objnum_to_String(int32u oid)
{
+#if ( SPREAD_PROTOCOL == 3 )
+
switch(oid)
{
case BASE_OBJ:
@@ -778,6 +912,8 @@
default:
return("Unknown_obj");
}
+#endif
+ return("Unknown_obj");
}
-#endif
+
Modified: libspreadutil/trunk/src/memory.h
===================================================================
--- libspreadutil/trunk/src/memory.h 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/src/memory.h 2012-01-31 05:26:05 UTC (rev 469)
@@ -83,6 +83,51 @@
*/
void dispose(void *object);
+
+/************************************************************************
+ * These functions are for reference count objects only.
+ * Basically they provide the same functionality as 'new' and 'dispose'
+ * only that they provide reference count functionality.
+ * Reference count functions can not be applied on non ref. count objects.
+ * and viceversa
+ ************************************************************************/
+
+/* Input: a valid type of object
+ * Output: a pointer to memory which will hold an object
+ * Effects: will only allocate an object from system if none exist in pool
+ * The allocated object will have reference counter initiated with 1
+ */
+void * new_ref_cnt(int32 obj_type);
+
+
+/* Input: a size of memory block desired
+ * Output: a pointer to memory which will hold the block
+ * Effects:
+ */
+void * Mem_alloc_ref_cnt(unsigned int length);
+
+/* Input: a valid pointer to a reference count object
+ * Output: the resulting reference count
+ * Effects: Increments the reference count of an object
+ */
+int inc_ref_cnt(void *object);
+
+
+/* Input: a valid pointer to a reference count object
+ * Output: the resulting reference count
+ * Effects: Decrements the reference count of an object.
+ * If the resulting reference count is 0, then the object is disposed
+ */
+int dec_ref_cnt(void *object);
+
+
+/* Input: a valid pointer to a reference count object
+ * Output: the reference count of the object
+ * Effects: Returns the reference count of an object.
+ */
+int get_ref_cnt(void *object);
+
+
/***************************************************************************
* These two functions are ONLY needed for dynamically sized allocations
* like traditional malloc/free --NOT for object based allocations
Modified: libspreadutil/trunk/src/sp_events.h
===================================================================
--- libspreadutil/trunk/src/sp_events.h 2012-01-30 14:12:21 UTC (rev 468)
+++ libspreadutil/trunk/src/sp_events.h 2012-01-31 05:26:05 UTC (rev 469)
@@ -77,6 +77,8 @@
int E_compare_time( sp_time t1, sp_time t2 );
int E_queue( void (* func)( int code, void *data ), int code, void *data,
sp_time delta_time );
+int E_in_queue( void (* func)( int code, void *data ), int code,
+ void *data );
/* Note: This does not dispose/free the data pointed at by the void
*data pointer */
int E_dequeue( void (* func)( int code, void *data ), int code,
More information about the Spread-cvs
mailing list