Added some more convenient error handling.
authorJustin Seyster <jseyster@cs.sunysb.edu>
Tue, 8 Mar 2011 02:33:03 +0000 (21:33 -0500)
committerJustin Seyster <jseyster@cs.sunysb.edu>
Tue, 8 Mar 2011 02:33:03 +0000 (21:33 -0500)
src/tracecut.c
src/tracecut.h
test/plugin-tracecut.c

index 17883c130a4281705d29f93e6fed7512b1f96155..d44d8172fb0b28a76f612da0010a65010faecc87 100644 (file)
@@ -91,6 +91,10 @@ struct tc_tracecut {
   /* Each symbol gets a unique index. */
   int next_symbol_index;
 
+  /* The first tracecut operation that fails stores its error code
+     here. */
+  enum tc_error tc_error;
+
   struct tc_tracecut *next;
 };
 /**
@@ -151,6 +155,52 @@ lookup_param (struct tc_tracecut *tc, const char *name)
   return NULL;
 }
 
+/* Here's a cool trick I learned from the DTrace source code.  This
+   function sets the error code in a tracecut object and also returns
+   that error code, so you can conveniently nestle it in the return
+   statement itself. */
+static enum tc_error
+return_error (struct tc_tracecut *tc, enum tc_error tc_error)
+{
+  /* The tc_error field holds the _first_ non success error code. */
+  if (tc->tc_error == TC_SUCCESS)
+    tc->tc_error = tc_error;
+
+  return tc_error;
+}
+
+/**
+ * The first operation on a tracecut that fails stores its error code
+ * in the tracecut.  This function returns that error code, or
+ * #TC_SUCCESS if all operations succeeded.  Checking error codes this
+ * ways makes it possible to call several tracecut functions in
+ * sequence without individually checking their error codes.
+ *
+ * Use tc_reset_error() to set a tracecut's error code back to
+ * #TC_SUCCESS.
+ *
+ * \param tc The tracecut to check.
+ * \return The error code of the first failed operation on this
+ * tracecut, or TC_SUCCESS if no operations failed.
+ */
+enum tc_error
+tc_error_code (struct tc_tracecut *tc)
+{
+  return tc->tc_error;
+}
+
+/**
+ * Clear the history of any failed operations on this tracecut.  After
+ * calling this, tc_error_code() will return #TC_SUCCESS until some
+ * later tracecut operation fails.
+ * \param tc The tracecut to reset.
+ */
+void
+tc_reset_error (struct tc_tracecut *tc)
+{
+  tc->tc_error = TC_SUCCESS;
+}
+
 /**
  * Add a new tracecut parameter.  Each tracecut tracks several
  * objects, so a tracecut event must be <i>parameterized</i> to
@@ -180,13 +230,13 @@ tc_add_param (struct tc_tracecut *tc, const char *name,
   struct tc_param *param = NULL;
 
   if (tc_in_compilation)
-    return TC_BAD_CONTEXT;
+    return return_error (tc, TC_BAD_CONTEXT);
 
   if (!aop_is_pointer_type (type))
-    return TC_INVAL;
+    return return_error (tc, TC_INVAL);
 
   if (lookup_param (tc, name) != NULL)
-    return TC_DUPLICATE;;
+    return return_error (tc, TC_DUPLICATE);
 
   param = (struct tc_param *)malloc (sizeof (struct tc_param));
   if (param == NULL)
@@ -203,11 +253,11 @@ tc_add_param (struct tc_tracecut *tc, const char *name,
   param->next = tc->param_list;
   tc->param_list = param;
 
-  return TC_SUCCESS;
+  return return_error (tc, TC_SUCCESS);
 
  nomem:
   free (param);
-  return TC_NOMEM;
+  return return_error (tc, TC_NOMEM);
 }
 
 static struct tc_call_symbol *
@@ -254,10 +304,10 @@ tc_add_call_symbol (struct tc_tracecut *tc, const char *name,
   struct tc_call_symbol *symbol = NULL;
 
   if (tc_in_compilation)
-    return TC_BAD_CONTEXT;
+    return return_error (tc, TC_BAD_CONTEXT);
 
   if (lookup_call_symbol (tc, name) != NULL)
-    return TC_DUPLICATE;;
+    return return_error (tc, TC_DUPLICATE);
 
   symbol = (struct tc_call_symbol *)malloc (sizeof (struct tc_call_symbol));
   if (symbol == NULL)
@@ -276,7 +326,7 @@ tc_add_call_symbol (struct tc_tracecut *tc, const char *name,
   symbol->next = tc->symbol_list;
   tc->symbol_list = symbol;
 
-  return TC_SUCCESS;
+  return return_error (tc, TC_SUCCESS);
 
  nomem:
   if (symbol != NULL)
@@ -285,7 +335,7 @@ tc_add_call_symbol (struct tc_tracecut *tc, const char *name,
       free ((char *)symbol->func_name);
       free (symbol);
     }
-  return TC_NOMEM;
+  return return_error (tc, TC_NOMEM);
 }
 
 static enum tc_error
@@ -299,11 +349,11 @@ add_call_symbol_binding (struct tc_tracecut *tc, const char *param_name,
   param = lookup_param (tc, param_name);
   symbol = lookup_call_symbol (tc, symbol_name);
   if (param == NULL || symbol == NULL)
-    return TC_NOENT;
+    return return_error (tc, TC_NOENT);
 
   binding = (struct tc_call_binding *)malloc (sizeof (struct tc_call_binding));
   if (binding == NULL)
-    return TC_NOMEM;
+    return return_error (tc, TC_NOMEM);
 
   binding->call_param_index = index;
   binding->param = param;
@@ -312,7 +362,7 @@ add_call_symbol_binding (struct tc_tracecut *tc, const char *param_name,
   binding->next = symbol->binding_list;
   symbol->binding_list = binding;
 
-  return TC_SUCCESS;
+  return return_error (tc, TC_SUCCESS);
 }
 
 /**
@@ -336,10 +386,10 @@ tc_bind_to_call_param (struct tc_tracecut *tc, const char *param_name,
                       const char *symbol_name, int call_param_index)
 {
   if (tc_in_compilation)
-    return TC_BAD_CONTEXT;
+    return return_error (tc, TC_BAD_CONTEXT);
 
   if (call_param_index < 0)
-    return TC_INVAL;
+    return return_error (tc, TC_INVAL);
 
   return add_call_symbol_binding (tc, param_name, symbol_name,
                                  call_param_index);
@@ -362,7 +412,7 @@ tc_bind_to_return_value (struct tc_tracecut *tc, const char *param_name,
                         const char *symbol_name)
 {
   if (tc_in_compilation)
-    return TC_BAD_CONTEXT;
+    return return_error (tc, TC_BAD_CONTEXT);
 
   return add_call_symbol_binding (tc, param_name, symbol_name, -1);
 }
@@ -385,25 +435,25 @@ tc_add_rule (struct tc_tracecut *tc, const char *specification)
   struct tc_rule *rule;
 
   if (tc_in_compilation)
-    return TC_BAD_CONTEXT;
+    return return_error (tc, TC_BAD_CONTEXT);
 
   rule = (struct tc_rule *)malloc (sizeof (struct tc_rule));
   if (rule == NULL)
-    return TC_NOMEM;
+    return return_error (tc, TC_NOMEM);
 
   /* TODO: Check syntax*/
   rule->specification = strdup (specification);
   if (rule->specification == NULL)
     {
       free (rule);
-      return TC_NOMEM;
+      return return_error (tc, TC_NOMEM);
     }
 
   /* Add this to the tracecut's list of rules. */
   rule->next = tc->rule_list;
   tc->rule_list = rule;
 
-  return TC_SUCCESS;
+  return return_error (tc, TC_SUCCESS);
 }
 
 /**
@@ -432,6 +482,7 @@ tc_create_tracecut (void)
   tc->next_symbol_index = 0;
   tc->param_list = NULL;
   tc->symbol_list = NULL;
+  tc->tc_error = TC_SUCCESS;
   tc->rule_list = NULL;
 
   /* Insert this tracecut into the master list. */
index 7bcfb3f38581f2d74a476bc9876e41678a98e5ee..64f017d8038e1ebb187b2f3f22202d6f1c81a333 100644 (file)
@@ -80,6 +80,9 @@ enum tc_error {
   TC_NOMEM,
 };
 
+extern enum tc_error tc_error_code (struct tc_tracecut *tc);
+extern void tc_reset_error (struct tc_tracecut *tc);
+
 extern enum tc_error tc_add_param (struct tc_tracecut *tc, const char *name,
                                   const struct aop_type *type);
 
index f6681d0d0bba5ff4e4703c22b1fdb353d9f48eec..cb2f49c6f253888b2be3b5a6ef9a2668e512bdef 100644 (file)
@@ -42,6 +42,8 @@ AOP_MAIN_PROTO aop_main()
 
   tc_add_rule(tc_foo, "get inc* dec");
 
+  aop_assert(tc_error_code(tc_foo) == TC_SUCCESS);
+
   /* Tracecut for bar objects. */
   tc_bar = tc_create_tracecut();
 
@@ -58,6 +60,8 @@ AOP_MAIN_PROTO aop_main()
 
   tc_add_rule(tc_bar, "get double* half");
 
+  aop_assert(tc_error_code(tc_bar) == TC_SUCCESS);
+
   /* Tracecut for both objects. */
   tc_both = tc_create_tracecut();
 
@@ -70,6 +74,8 @@ AOP_MAIN_PROTO aop_main()
 
   tc_add_rule(tc_both, "transfer transfer");
 
+  aop_assert(tc_error_code(tc_both) == TC_SUCCESS);
+
   aop_register_pass("init_tracecut", init_pass);
   tc_register_tracecut_pass();
 }