[Swift-commit] cog r3952

swift at ci.uchicago.edu swift at ci.uchicago.edu
Mon Jun 23 16:10:03 CDT 2014


------------------------------------------------------------------------
r3952 | timgarmstrong | 2014-06-23 16:05:18 -0500 (Mon, 23 Jun 2014) | 1 line

Add in facility to store error info.
------------------------------------------------------------------------
Index: modules/provider-coaster-c-client/src/coasters.cpp
===================================================================
--- modules/provider-coaster-c-client/src/coasters.cpp	(revision 3951)
+++ modules/provider-coaster-c-client/src/coasters.cpp	(working copy)
@@ -25,6 +25,7 @@
 
 #include <cassert>
 #include <cstdlib>
+#include <pthread.h>
 
 #include "CoasterClient.h"
 #include "CoasterError.h"
@@ -36,7 +37,7 @@
 using std::string;
 
 /*
-  Struct just wraps the object
+  Struct just wraps the objects
  */
 struct coaster_client {
   CoasterLoop loop;
@@ -46,27 +47,41 @@
     Constructor: initialize loop then client
    */
   coaster_client(string serviceURL) :
-        loop(), client(serviceURL, loop) {
+        loop(), client(serviceURL, loop) { }
+};
 
-  };
+struct coaster_err_info {
+  string msg;
+
+  coaster_err_info(const string _msg): msg(msg) {}
 };
 
+static pthread_key_t err_key;
+static pthread_once_t err_key_init = PTHREAD_ONCE_INIT;
+
+static coaster_rc coaster_return_error(coaster_rc code,
+                                    const string &msg);
 static coaster_rc coaster_error_rc(const CoasterError &err);
 static coaster_rc exception_rc(const std::exception &ex);
+static void init_err_key(void);
+static void cleanup_err_key(void *errinfo);
+static void clear_err_info(void);
 
 // Check for error
-// TODO: store error message somewhere instead of printing?
 #define COASTER_CONDITION(cond, err_rc, err_msg) { \
-  if (!(cond)) { fprintf(stderr, (err_msg)); return (err_rc); }}
+  if (!(cond)) { coaster_return_error((err_rc), (err_msg)); }}
 
+// TODO: it's bad that this might allocate memory
+#define COASTER_CHECK_MALLOC(ptr) { \
+  if ((ptr) == NULL) { \
+    coaster_return_error(COASTER_ERROR_OOM, "out of memory"); }}
+
 coaster_rc
 coaster_client_start(const char *service_url, size_t service_url_len,
                     coaster_client **client) COASTERS_THROWS_NOTHING {
   try {
     *client = new coaster_client(string(service_url, service_url_len));
-    if (!(*client)) {
-      return COASTER_ERROR_OOM;
-    }
+    COASTER_CHECK_MALLOC(*client);
 
     (*client)->client.start();
     return COASTER_SUCCESS;
@@ -98,9 +113,7 @@
                                 COASTERS_THROWS_NOTHING {
   try {
     *settings = new Settings();
-    if (!(*settings)) {
-      return COASTER_ERROR_OOM;
-    }
+    COASTER_CHECK_MALLOC(*settings);
  
     return COASTER_SUCCESS;
   } catch (const CoasterError& err) {
@@ -159,15 +172,13 @@
 
     // Use malloc so C client code can free
     *keys = (const char**)malloc(sizeof((*keys)[0]) * (*count));
-    if (!(*keys)) {
-      return COASTER_ERROR_OOM;
-    }
+    COASTER_CHECK_MALLOC(*keys);
     
     if (key_lens != NULL) {
       *key_lens = (size_t *)malloc(sizeof((*key_lens)[0]) * (*count));
       if (!(*key_lens)) {
         free(*keys);
-        return COASTER_ERROR_OOM;
+        COASTER_CHECK_MALLOC(*key_lens);
       }
     }
     
@@ -205,7 +216,7 @@
                                   coaster_settings *settings)
                                   COASTERS_THROWS_NOTHING {
   if (settings == NULL || client == NULL) {
-    return COASTER_ERROR_INVALID;
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid arg");
   }
 
   try {
@@ -259,7 +270,7 @@
       const char *stderr_loc, size_t stderr_loc_len)
                   COASTERS_THROWS_NOTHING {
   if (job == NULL) {
-    return COASTER_ERROR_INVALID;
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid arg");
   }
   
   try {
@@ -288,7 +299,7 @@
 coaster_job_set_directory(coaster_job *job, const char *dir, size_t dir_len)
                   COASTERS_THROWS_NOTHING {
   if (job == NULL) {
-    return COASTER_ERROR_INVALID;
+    return coaster_return_error(COASTER_ERROR_INVALID, "");
   }
   
   try {
@@ -309,7 +320,7 @@
       const char **names, size_t *name_lens,
       const char **values, size_t *value_lens) COASTERS_THROWS_NOTHING {
   if (job == NULL) {
-    return COASTER_ERROR_INVALID;
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid arg");
   }
   
   try {
@@ -342,7 +353,7 @@
         const char **values, size_t *value_lens) COASTERS_THROWS_NOTHING {
  
   if (job == NULL) {
-    return COASTER_ERROR_INVALID;
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
   }
   
   try {
@@ -371,7 +382,7 @@
         COASTERS_THROWS_NOTHING {
  
   if (job == NULL) {
-    return COASTER_ERROR_INVALID;
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
   }
   
   try {
@@ -403,7 +414,8 @@
                                             COASTERS_THROWS_NOTHING {
   const JobStatus *status;
   if (job == NULL || (status = job->getStatus()) == NULL) {
-    return COASTER_ERROR_INVALID;
+    return coaster_return_error(COASTER_ERROR_INVALID,
+                                "invalid or unsubmitted job");
   }
   
   *code = status->getStatusCode();
@@ -416,7 +428,7 @@
                 const char **stderr_s, size_t *stderr_len)
                 COASTERS_THROWS_NOTHING {
   if (job == NULL) {
-    return COASTER_ERROR_INVALID;
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
   }
 
   const string *out = job->getStdout();
@@ -458,7 +470,7 @@
                    coaster_job **jobs, int *njobs)
                 COASTERS_THROWS_NOTHING {
   if (client == NULL) {
-    return COASTER_ERROR_INVALID;
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid client");
   }
   
   try {
@@ -495,17 +507,82 @@
   }
 }
 
+const char *coaster_last_err_info(void) {
+  // Ensure initialized
+  pthread_once(&err_key_init, init_err_key);
+
+  void *val = pthread_getspecific(err_key);
+  if (val == NULL) {
+    return NULL;
+  }
+
+  coaster_err_info *info = static_cast<coaster_err_info *>(val);
+  return info->msg.c_str();
+}
+
+static void init_err_key(void) {
+  pthread_key_create(&err_key, cleanup_err_key);
+}
+
 /*
+ * Called to cleanup error key
+ */
+static void cleanup_err_key(void *errinfo) {
+  delete static_cast<coaster_err_info*>(errinfo);
+}
+
+static void set_err_info(const string& msg) {
+  // Ensure key is initialized
+  pthread_once(&err_key_init, init_err_key);
+
+  void *prev = pthread_getspecific(err_key);
+  if (prev != NULL) {
+    cleanup_err_key(prev);
+  }
+  
+  coaster_err_info *err_info = new coaster_err_info(msg);
+  pthread_setspecific(err_key, static_cast<void*>(err_info));
+}
+
+static void clear_err_info(void) {
+  void *prev = pthread_getspecific(err_key);
+  if (prev != NULL) {
+    cleanup_err_key(prev);
+  }
+  
+  pthread_setspecific(err_key, NULL);
+}
+
+/*
+ * Helper to set error info when returning error.
+ */
+static coaster_rc coaster_return_error(coaster_rc code,
+                                    const string& msg) {
+  set_err_info(msg);  
+  return code;
+}
+
+/*
  * Set error information and return appropriate code
  */
 static coaster_rc coaster_error_rc(const CoasterError &err) {
-  // TODO: store detailed error info
+  const char *msg = err.what();
+  if (msg != NULL) {
+    set_err_info(string(msg));
+  } else {
+    clear_err_info();
+  }
   // TODO: distinguish different cases?
   return COASTER_ERROR_UNKNOWN;
 }
 
 static coaster_rc exception_rc(const std::exception &ex) {
-  // TODO: store error info?
+  const char *msg = ex.what();
+  if (msg != NULL) {
+    set_err_info(string(msg));
+  } else {
+    clear_err_info();
+  }
   // TODO: handle specific types, e.g. bad_alloc
   return COASTER_ERROR_UNKNOWN;
 }
Index: modules/provider-coaster-c-client/src/CoasterError.cpp
===================================================================
--- modules/provider-coaster-c-client/src/CoasterError.cpp	(revision 3951)
+++ modules/provider-coaster-c-client/src/CoasterError.cpp	(working copy)
@@ -9,11 +9,13 @@
 #include <stdlib.h>
 
 CoasterError::CoasterError(string msg) {
+	// TODO: this stores pointer to string of unknown lifetime
 	message = msg.c_str();
 }
 
 CoasterError::CoasterError(const char* format, ...) {
 	va_list args;
+        // TODO: this isn't freed
 	char* buf = (char *) malloc(MAX_MSG_LEN + 1);
 
 	va_start(args, format);
@@ -23,6 +25,7 @@
 }
 
 CoasterError::CoasterError(const stringstream* ss) {
+	// TODO: this stores pointer to string of unknown lifetime
 	message = ss->str().c_str();
 }
 
Index: modules/provider-coaster-c-client/src/coasters.h
===================================================================
--- modules/provider-coaster-c-client/src/coasters.h	(revision 3951)
+++ modules/provider-coaster-c-client/src/coasters.h	(working copy)
@@ -286,6 +286,15 @@
  */
 const char *coaster_rc_string(coaster_rc code);
 
+/*
+ * Get additional information about last returned error in current
+ * thread.
+ * returns: error message, NULL if no information available.  The
+ *          returned string is valid until the next call by this thread
+ *          to a coasters API function.
+ */
+const char *coaster_last_err_info(void);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif



More information about the Swift-commit mailing list