[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